Starting Flow in 2020

Brian Chen
The Startup
Published in
8 min readAug 1, 2020
Photo by @annietheby from Unsplash

It’s 2020 and you do a search for “state of flow in 2020”. You’ll find some blogs from Flow, maybe some blogs comparing Flow with TypeScript, some unrelated stuff with the keyword “flow” and maybe this blog. Really not that much.

But 2020 was the year I started using Flow and at this point I would never consider going back to vanilla JavaScript. I’m going to be sharing my journey with Flow in this post, but if you’re looking for a getting started guide you may have to look elsewhere.

I’ve been developing in JavaScript with React for around 5 years. I’ve used Java in the past but I really enjoyed the dynamic nature of JS and never really missed the types. Plus you can do cool things like const [value, setValue] = useState() where the first index could be a string and the second a function.

So 2020 roles around and I’m happily coding JS, and working on a company internal component library. There’s quite a wide usage at this point and I’m thinking, how can I ship code that’s more stable, reliable, and won’t have random introduction of bugs. I’m already running unit tests and usability interaction tests with Enzyme/React-testing-library and storybook respectively.

I began my search and it turned out what I was looking for was exactly Flow’s goal, soundness.

“The state of being in good condition; robustness.”

For reference, in comparison to TypeScript their major goal is completeness. There’s a really great video that goes into depth on the differences here, https://youtu.be/uJHD2xyv7xo.

I was quite happy with my current tooling, transpiling with Babel, Airbnb eslint configs, etc. So it made me happier to know that Flow works as a supplementary tool that you simply bolt to your existing toolchain. It also allowed me to incrementally add Flow to my library, which was major as I could use it internally in the project until I was ready to expose it to my consumers.

I wrote a small bash script that kept track of all flow typed files and when I finally migrated all my source code, I added it to my lint-staged config.

#!/bin/bash
targetFolder="src"
files=$(find ${targetFolder} -type f)
echo "The following files are not flow typed, consider adding \"// @flow\" to the top of the file"
echo "---"
notype=()for f in ${files}; do
value=`cat ${f}`
if [ "${value:0:8}" != '// @flow' ]; then
notype+=($f)
echo ${f}
fi
done
echo "---"# Pass or fail check
if [ ${#notype[@]} -eq 0 ]; then
echo "✨ All src files flowtyped, congrats! 🎉"
else
echo "💥 Please flowtype the files above and try again"
exit 1
fi

You can also use flow-coverage-report, though because it parses and runs a report it’s a bit slower and probably won’t work as well as a git hook.

The good, the bad, the ugly

During my time learning, I found quite a lot of negative feedback as well as my own short comings.

These in no way turned me off obviously, they may for you, but I think it’s important to set the expectations of a new user correctly so they don’t jump in only to be disappointed because they expected something different.

First, the learning curve I found very steep, and the documentation doesn’t do it justice. Sometimes it’s very comprehensive and other times parts of the documentation are straight up missing or it’s not clear where to look.

What made it more challenging was I had to figure out how to do things that were specific to shipping a library. Sometimes I’d spend days working on a single problem, with 20+ tabs deep into the rabbit hole. Though it was rewarding to find the answer.

Once I got the hang of it, I found the tool extremely fluid and I naturally found myself coming across less soundness errors by mistake because I was coding differently.

I say soundness errors and not type errors, because I believe that Flow is a soundness tool first and a type checker as a consequence. For example, you may be familiar with the first lines of code you’ll ever write with react as

import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<div>Hello World</div>,
document.getElementByTestId('root'),
);

But with Flow it enforces guards around your code to prevent as many runtime errors as possible. So you would have to do this instead.

// @flow
import React from 'react';
import ReactDOM from 'react-dom';
const element = document.getElementByTestId('root');if (element) {
ReactDOM.render(
<div>Hello World</div>,
element,
);
}

It may seem super trivial and rather pointless but this is something I like. It’s putting rational guardrails up for my code so that I’m naturally nudged into better standards.

One thing to note while I’m showcasing the first code snippet of Flow is that unlike TypeScript, Flow does not block any kind of compilation. Again this is something I’m a fan of. Although Flow will tell you there’s an error in your code, it doesn’t force that it’s correct, because in the end, it’s a static type checker that’s based on human written type definitions which doesn’t run real code. In very complicated scenario’s it could very well be wrong.

// $FlowFixMe
const isIcon = children?.type?.displayName === 'Icon';

Consider the react code snippet above, which I’ve tested to work across use cases and browsers, but Flow tells me it’s wrong, I haven’t figured out the right way to type this yet, but with Flow, I’m able to test this because compiling isn’t blocked and I can add suppression comments so I can come back later.

Overall I found that issues I came across were never a limitation of the tool, but of my understanding.

Second, which is one of the biggest deterrents of Flow is that the community and support is limited.

If you want to ask for help, the 3 main places you’ll go are:

The issue is that most of these places are quite barren, there may be 0–3 active people who will try to support you per question and getting answers from the maintainers of Flow are quite hit or miss regardless of the platform they’re asked in. I’ve personally tried to help where I can but with my lack of experience I can only go so far. It’s quite a shame really, there are still quite a lot of people picking up and trialing Flow for the first time but they’re not getting the support required to see the benefits.

Another issue is that there’s no official support from flow to help developers ship type definitions in their libraries in a consistent way.

Like TypeScript’s DefinitelyTyped repo, Flow has their own flow-typed repo where the community can come together and add type definition to libraries that may be written with vanilla JS or TypeScript. There’s quite a healthy number of definitions supported, and you’ll probably run into no issues if you you use the community standard libraries such as jest enzyme moment redux , it’s when you start to use obscure packages that you’ll come into issues. Of course you won’t be blocked in your development, flow-typed will help you stub any packages that don’t have type definitions with any type but you’ll find Flow a lot less helpful when this happens.

Flow-typed recommends you fill in your stub and submit a pull request to help the rest of the community. I’ve done this a few times, and the maintainers there are quite active, so it’s actually a really great and easy way to contribute back to the Flow community.

The main issue with Flow that others have highlighted, is that Flow’s requirements come from Facebook internally. They don’t have the same requirements to ship third party libraries or ask questions on a forum because I assume they all use the same centralised tooling and they can just ask the guy next to them if they need help.

But it’s not all bad, this does mean that Flow is backed 100% by Facebook and there’s always a constant steady stream of changes published every few weeks. Like the recent release of their types-first architecture which is supposed to provide immensely improved performance, because one thing that Flow constantly touts, is that is that Facebook’s codebase is extremely massive compared to everyone else’s.

Besides Facebook, I was quite happy to see a few other popular libraries and companies that use Flow:

  • Facebook and their open source tools (React, GraphQL, Recoil, etc)
  • VueJS
  • Uber and their BaseWeb component library
  • Styled-components
  • Emotion
  • Khan Academy and and their libraries Aphrodite and Wonder Blocks
  • Parcel bundler
  • Redux-form and react-final-form (though the maintainer expressed he wants to move to TypeScript)

So you can see that although Flow isn’t popular, it’s definitely not dead. It’s worth giving a try or picking up again if you used it a few years ago as I imagine the developer experience is much improved. I haven’t had any troubles personally.

From what I’ve heard, my personal thoughts are, I think when Flow first released people tried it and there were many issues such as constant breaking changes with new releases and a poor development experience. This made the library lose a lot of traction. In case you didn’t know Flow releases new versions under 0.X.0, meaning it’s in beta essentially. This turns a lot of people off because they question the stability of the product, but I think this is a very reasonable decision by the people from Flow, because although this is a mature product, they’re still experimenting, seeing what fits and applying changes to the architecture, they don’t want to provide a false promise that you can blindly upgrade your package every time there’s a release and there’ll be no work from your end.

But I think at this point it’s quite stable, I’ve used it since 0.121.0 (it’s on 0.130.0 at the time of writing) and I’ve had no issues upgrading within a few days of new releases. Sometimes new Flow errors appear after an upgrade but that’s more because Flow was able to better infer type errors as opposed to random false positives.

And for those that aren’t shipping libraries it’s even easier because you don’t need to consider the downstream impact, if you get no errors you’re good to go.

Overall, I love Flow. I think it’s an awesome tool that does what it needs to, it’s rough around the edges but I’ve seen improvements and promises this year that excites me for the future.

I’ll end by leaving my wish list for what I’d like to see in the future, they may not come from the Flow team directly, maybe you can help:

  • More activity from Flow maintainers or some community managers that help answer questions or direct users to correct sources
  • A more active community, contributions to flow-typed to make it more inviting to new users, refined supporting tools, answering questions
  • Improvements to the documentation and a better quick start guide that encourages config settings that eventually will be enabled by default
  • Official support and direction for shipping types with libraries

As you may notice, I have no issues with the tool itself, I believe it works just the way it should (mostly, I know there are bugs). It just has a massively steep learning curve with no clear direction on how to get to the top.

If you have actual issues with the tool drop a comment, I’d be keen to hear your limitations.

--

--