Flow - JavaScript Static Type Checker

Updated Aug 26, 2021#javascript#tooling#reviews

Flow is an open-source static type checker for JavaScript, written in OCaml, backed by Facebook, checks your code for errors through static type annotations, stripped away in production, and easy to insert into your existing workflow and toolchain.

// @flow
function square(n: number): number {
  return n * n
}

square('2') // Error!

It is designed to understand idiomatic JavaScript, infers types and tracks data as it moves through your code, gives you fast feedback while you code by incrementally rechecking your code as you make changes, and integrates well with many tools.

Motivation

Type safety in JavaScript is weak (implicitly type conversion) and dynamic (checked at runtime). This facilitates fast prototyping but loses all benefits like caching errors early at compile time, auto completion, and performance optimization.

Evolving and growing a JavaScript codebase is notoriously challenging. Developers cannot move fast when they break stuff. They hit frequent interruptions, spending a lot of time debugging silly mistakes, unraveling assumptions and guarantees made by libraries written by others, etc.

This overhead can be mitigated by adding a layer of types to the codebase, and building tools that use type information to solve the above problems.

Several useful type systems have been built for JavaScript in recent years to mimic statically-typed languages (C/C++, Java, Rust, Go, Scala, etc.) and take advantage of static code analysis. Making you code faster, smarter, more confidently, and to a bigger scale.

Currently, the most popular type checking libraries are TypeScript, which is backed by Microsoft, and Flow, developed by Facebook.

Popular frameworks like Angular, Vue, Electron and Nuxt fully support TypeScript for development. By contrast, you need to integrate Flow manually into many popular frameworks, except React which supports Flow by default.

Getting Started

Flow was created to deliver an immersive coding experience for JavaScript developers with precision and speed in mind, can be adopted incrementally and easily removed at anytime.

There are a few ways to setup Flow depending on what tools you’re already using. To use Flow, you need to:

Type Annotations

Adding type annotations is an important part of your interaction with Flow. It has a powerful ability to infer the types of your programs. The majority of your code can rely on different Flow types like primitives, literal, any, mixed, maybe, variable, function, object, class, tuple, interface, union, and many more.

Following is an example JavaScript snippet annotated with Flow types:

// @flow

// Typing function declarations and values
function concat(a: string, b: string): string {
  return a + b
}

concat('foo', 'bar') // Works!
concat(true, false) // Error!

// Typing tuple-like array values
let tuple: [number, boolean, string] = [1, true, 'three']
tuple[0] = 2 // Works!
tuple[0] = 'bar' // Error!

// Typing values that may be one of many different types
function toStringPrimitives(value: number | boolean | string) {
  return String(value)
}
toStringPrimitives(1) // Works!
toStringPrimitives({prop: 'val'}) // Error!

If you want a way to opt-out of using the type checker, any is the way to do it. Using any is completely unsafe, and should be avoided whenever possible.

When you start a project with Flow, you likely want to use some third-party libraries that were not written with Flow. By default, Flow will just ignore these libraries leaving them untyped. As a result, Flow can’t give errors if you accidentally mis-use the library (nor will it be able to auto-complete the library).

To address this, Flow supports library definitions which allow you to describe the interface of a module or library separate from the implementation of that module/library.

The flow-typed repo is a collection of high-quality library definitions, tests to ensure that definitions remain high quality, and tooling to make it as easy as possible to import them into your project.

Flow reports many different kinds of errors for many common programming mistakes, but not every JavaScript pattern can be understood by Flow. If you are confident your code is correct, and that Flow is erroring too conservatively, you can suppress the error so that Flow does not report it.

// $FlowFixMe
// $FlowIssue[incompatible-type]
/* $FlowIgnore[prop-missing] some other text here */

You can enable stronger safety guarantees in Flow (such as banning any/Object/Function types and requiring all dependencies to be typed) by adding @flow strict to your files.

Summary

Flow provides static type checking to JavaScript which can both help find and detect bugs long before code is deployed and can make code easier to read and more self-documenting.

The Flow tool itself only reads and analyzes code. Running code with Flow type annotations requires first removing the annotations which are non-standard JavaScript.

As of this writing, TypeScript is the more popular choice over Flow.