Tips and Tricks for Flow — a static type checker for JavaScript

Flow is a static type checker for JavaScript. It makes it less likely to introduce bugs as the ‘Type’ of the data flowing through the system are tracked. (More about static and dynamic types are here).

There are 2 things to have ready in order to use Flow in Webpack.

Flow-bin is the binary that interprets the flow type annotations and enables static type checking. Since the types are just to help reduce bugs in development, we need to strip away the types before we send the JavaScript to the browser. The installation guide suggests installing babel-preset-flow for babel to compile. Digging into the source code, you will see that this preset depends on babel-plugin-transform-flow-strip-types. If you happen to have babel-preset-env configured in Webpack for transpiling JSX, the good news is — it would have handled Flow for you already! babel-preset-env has included babel-plugin-transform-flow-strip-types as one of the plugins so there is no need to install and configure babel-preset-flow.

The babel-loader would automatically does the work of stripping off the flow annotation as long as the preset of either ‘env’ or ‘flow’ is specified in the .babelrc. No additional configuration is required in webpack.config.js.

Something to be careful with Flow

Flow can also integrate with editors and enable on-the-fly linting without having to flow check on the terminal separately. To enable Flow-Language-Support on VScode, Flow needs to be installed globally even though it is not recommended.

I had an issue in a new project where Flow kept complaining about React.ComponentType is not exported from React even though I already npm installed the latest Flow in the project. The Flow project includes the React types so it is not likely due to the React 15 to React 16 upgrade…

After a long debugging process, I noticed that the flow version was not the latest version installed for the project.

which flow shows that the flow server used was from /usr/local/bin/flow , the global Flow… which should have been obvious since the command flow is only available when flow is installed globally. Otherwise we need to use project specific flow via node_modules/.bin/flow.

To remove and reinstall global Flow

npm uninstall -g flow-bin
npm install -g flow-bin

Now, the VSCode flow plugin should work with the new project. It, however, may appear to be broken on old projects which still depend on older version of flow… If upgrading Flow in old projects is too much trouble, using project specific node_modules/.bin/flow check should work around the issue for now.

Note: To use project specific Flow binary instead of global Flow, we can set the following setting in VSCode.

"flow.useNPMPackagedFlow": true

One take away: if something straight forward should work but doesn’t, and there is not much clue on the documentation and stackoverflow and github issues=> Triple check the versions!

Useful Technique: Type Casting

An annoying Flow issue that I bumped into is usually from the issue of other common methods by third-party library. For instance:

const hoveredDom = findDOMNode(component).getBoundingClientRect();

Initially, Flow complains about .getBoundingClientRect() can not be called on potentially null value. After doing the usual check to ensure findDOMNode(component) is not null, Flow complains getBoundingClientRect() can not be called on Type Text… because findDomNode can return either of null | Element | Text according to the prebuilt Flow types. In my case, I know findDOMNode(component) will return me an Element for sure. To restrict the return type to be just Element, we can use Type Casting Through Any! To cast a type to be more specific, we can use the magical any. Flow then stops complaining!

const componentDom = ((findDOMNode(component): any): Element);const hoveredDom = componentDom.getBoundingClientRect();

Useful Technique: Mocking FlowTypes

Sometimes we don’t need to have the type definitions for the libraries we use. e.g. the performance monitoring tool, why-did-you-update. In this case, when Flow complains about “required module not found” in that library, we can mock one up by using the method specified here.

// mocking file declare module 'invariant' {
declare module.exports: any;
}

Another method is to use flow-typed library to download/generate the type definitions.

Other Useful Resources

Use CSSModules with Flow.

//.flowconfig
[options]
module.name_mapper.extension='css' -> '<PROJECT_ROOT>/flow/CSSModule.js.flow'

A software engineer passionate about learning and growth