Background
Despite seeing the JS community slowly moving away from Flow to TypeScript, Shopee Web Frontend codebase is still very much stuck with Flow. 😨
After some silence, Flow has come back and committed to be a more efficient, reliable and friendly tool. Thus, we decided to give Flow a final chance. However, in order to enjoy the improvements that Flow has made in recent days, we have to upgrade Flow from 0.83 (since our last update) to v0.97 (latest to date), which meant that we need to upgrade past v0.85, which meant hell to codebase that uses react-redux extensively.
One of our brave developer, Gao Wei took up the challenge and decided to bring us to the bright side of Flow. 😅. She twitted and wrote an article on how she fixed the errors arose in the process.
To put the problem in perspective, from Flow 0.85 onwards, Flow is asking for required annotations for implicit annotations. Or less technical, if you are trying to export
something that was created from a generic class (eg: class Foo<T>
) or functions (eg: function foo<T>(){}
), without explicit type arguments (eg: new Foo<Type>()
or foo<Type>()
), Flow is going to give you an error.
Or in layman terms, if your repo is full of HOCs or connect()
, you are f**ked. So, be sure the check Gao Wei's blog if you are one of the brave souls upgrading a Flow project.
The Tooling
In this article, I would like to list out some of the roadblocks we encountered that was less well discussed, the tooling for the latest Flow syntax, which is the TypeParameterInstantiation
, eg: calling a function or instantiation a class with a type parameter, new Foo<Type>()
or foo<Type>()
.
Babel & Eslint
We had to upgrade our babel to babel v7 and babel-eslint (a babel wrapper for eslint) to babel-eslint v9 to support this new syntax.
You can read about on how we came to realise the need of this upgrade in my previous post.
There was another interesting bug that we ran into regarding @babel/plugin-transform-flow-strip-types, you can read more on how we uncover it in my other blog post.
Prettier
We had to upgrade prettier to v1.16.0 and use babel-flow
parser for prettier
to resolve the ambiguity in syntax arise in parsing the newer Flow syntax. In simpler terms, to tell Prettier that
foobar<Type>(1)
is calling foobar with argument, 1 and type, "Type", instead of:
foobar < Type > 1
is the result of foobar < Type, greater than 1? 😂
You can read more about it in Prettier's blog post.
VSCode
Flow Lazy Mode has been around since v0.68, but we hadn't enjoy the benefit of lazy mode through VSCode until recently.
Now we can specify lazyMode
in our .vscode/settings.json
:
{
"flow.useLSP": true,
"flow.lazyMode": "ide"
}
Although lazy mode reduces the scope where Flow does type checking, one of the pain point we had with Flow was to wait for Flow to do recheck, before returning a meaningful Flow status again. Flow team did some optimisation in v92.0, where it says:
This release culminates months of hard work on quality of life improvements for IDE support. Expect your requests to be faster, and your requests to take a bit less time.
According to the release note, Flow is now able to provide type definitions while rechecking, for further details on how they achieve this, you can read the Flow blog
Closing remarks
Finally we managed to get Flow running in v0.97 🎉. We've been struggling with bad developer experience with v0.83 for the longest time, hopefully v0.97 do not let us down.
Lastly, be sure to check out all the links sprinkled throughout this blog, they link to Github issues, commits, release notes, and who knows it might lead you to some unexpected adventures? 🤷
But if you are lazy like me, here are the links, they served as my references when writing this blog post:
- Blog: Incremental Migration to TypeScript on a Flowtype codebase
- Blog: Porting 30k lines of code from Flow to TypeScript
- Issue: What is the official way to type connect ( from flow-typed/react-redux) after 0.85?
- Issue: [react-redux] libdef incompatible with flow v0.85 #2946
- Tweet: It's so hard to make flow happily get past 0.85 with our codebase...
- Blog: Making Flow Happy after 0.85
- Blog: Asking for Required Annotations
- Docs: Babel 7 Migration
- Release Note: babel-eslint v9.0.0
- Docs: @babel/plugin-transform-flow-strip-types
- Release Note: Prettier v1.16.0
- Commit: Lazy mode message for flow status
- Commit: feat(lsp): add setting to support flow lazyMode.
- Docs: Flow Lazy Mode
- Release Note: Flow v0.92.0
- Blog: A more responsive Flow