inato
Published in

inato

Migrating from Flow to Typescript: Why? How? Worth it?

Photo by Gary Bendig on Unsplash

When I arrived at Inato, the codebase was written in ES6. Then, we added some robustness with Flow. It helped us perform major refactors and lower our bug count. We were happy… until problems showed up.

Problems we had with Flow

  • Flow takes a lot of RAM and computing resources (we witnessed > 10 Go of RAM).
  • The integration with text editors is not state-of-the-art. We could not find a way to make auto-completion and auto-imports work in VSCode.
  • There is no official support for exporting type definitions from a module (this is painful when we split our code into different modules)
  • For some npm packages, either typings are missing in flow-typed, or typings are incomplete / out of date. For instance formik and styled-components have poor flow definitions. This makes the code less safe.

Project-specific problems we had with Flow

  • React typings are bound to Flow’s version. After we upgraded React to 16.8.4 in order to use hooks, we wrote some unsatisfying $FlowFixMe
  • In thereact-relay library, the typing of createFragmentContainer is wrong, and breaks the type safety for numerous components. (see the GitHub issue)

Exploring alternatives to Flow

What are the other typed languages that compile to Javascript? Typescript and ReasonML seem to be the best candidates.

  • ReasonML produces very safely typed code. The syntax is quite different from ES6 though, and the ecosystem looks young.
  • Typescript is a great typed language with a large community. The ecosystem is mature and the syntax is similar to ES6. This is obviously the best choice for us.

How to migrate to Typescript

  • If you use Flow, you probably use Babel. Upgrade to babel 7 to use the Typescript preset.
  • Install typescript (yarn install typescript)
  • Add a tsconfig.json file at the project root. Use"strict": false in the compiler options.
  • Change the file extensions from .js to .ts (or .tsx if your project uses JSX). You can run this command to rename all files at once in the .ts extension:
find src -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.ts"' {} \;
  • Monitor the errors: yarn tsc --noEmit --watch. You will see a lot of syntax errors. You can fix most of them with a couple of regexes:
Search and replace:{|{
|}}
import typeimport
$ReadonlyArrayReadonlyArray
$NonMaybeTypeNonNullable
Regexes:\+(\w+) ⇒ readonly $1
: \?(\w+<?\w*>?) ⇒ : $1 | null | undefined
<\?(\w+)> ⇒ <$1 | null | undefined>
\$PropertyType<(\w+), ('?\w+'?)> ⇒ $1[$2]
  • After your syntax errors count has gone to 0, you will see a lot of new errors. These are type errors ! There is no generic way to fix them, handle them one by one (this is the longer part of the process).
  • Update your babel config. It should look like this:
{
"presets": ["@babel/env", "@babel/typescript"],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread"
]
}
  • Update your linter. If you’re using ESLint, use @typescript-eslint
  • Update your test suite. If you’re using Jest, use ts-jest

Is it worth it?

YES! Definitely!
We’ve eliminated almost all problems we had with Flow. We’re still having small issues with composite projects, but overall it’s a great improvement.

  • The Typescript integration in VSCode is impressive: auto-imports and auto-complete work.
  • We have no more inconvenient RAM usage.
  • DefinitelyTyped contains a lot of typings and the quality of these typings is great overall. No more problems with react and react-relay typings.
  • It’s easy to export type definitions => it encourages developers to split their code into smaller packages (which I think is a good practice)

It’s too soon to witness the impact on our productivity, so I measured the impact on the “Developper Happiness” among team members. I’m assuming that happy coding is correlated with less problems and higher productivity. Here are the results:

Conclusion

Flow is a great tool a lot of people are happy with. But it has some limitations when the codebase becomes big. If you’re experiencing the same problems as we did, I strongly recommend to migrate.

--

--

--

Thoughts & experiences from the Inato team

Recommended from Medium

THE BEGINNER’S GUIDE TO UNDERSTANDING OBJECT DESTRUCTURING IN JAVASCRIPT

Stripe Payment Integration in React-Native -Part III

Currying in Javascript (tersely explained)

Seven In One: “My Form” WebApp using VueJS+Vuetify+Firebase Hosting PART III

8 React Application Deployment and Hosting Solutions for 2019

How to set up Google Analytics in your React App with React Router without using react-ga

Using React Hooks in Redux Application

RxJS: Understanding Expand

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Samuel Briole

Samuel Briole

Senior full-stack engineer

More from Medium

Type safety with JSDocs

Explanation Utility Types in TypeScript

Sharing React Query across micro frontends with single-spa and webpack module federation

Writing unit tests in typescript using jest.