Requiring More Annotations to Functions and Classes in Flow

Sam Zhou
Flow
Published in
2 min readSep 30, 2022

As announced in our Local Type Inference post, Flow is changing the way its type checking algorithm works. The changes will enable new features in Flow and give better error messages. To enable these exciting new features, we will be requiring more annotations in some cases.

This new behavior is currently behind enforce_local_inference_annotations=true. It will be turned on by default in 0.189.0, and the old behavior won’t be supported starting from 0.190.0.
Enabling the flag will likely cause errors in your project. We are providing codemodding tools to help ease the transition, and you can find detailed instructions for upgrading at the end of this article.

This will not be the only language change we are planning. In the next several months, we will incrementally roll out more requirements (e.g. annotation requirements on empty array) to prepare your codebase for enabling local type inference eventually.

What we are targeting first

The biggest change is requiring annotations for most function parameters (but not function return types). This was already the case for exported function definitions, but we are now expanding it to cover the majority of functions. Any function not defined as an inline callback will need annotations. For example:

// Before
function addOne(x) {
return x + 1;
}
// After: Parameter needs an annotation
function addOne(x: number) {
return x + 1;
}

However, something like the following will not require annotations:

[1, 2, 3].map(x => x + 1);

Additionally, functions using this that are outside of class methods will need to have the type of this explicitly annotated:

// Before
function phoneHome() {
this.phone('Home');
}
// After: "this" needs an annotation
function phoneHome(this: {phone: string => void}) {
this.phone('Home');
}

Finally, classes must be fully annotated:

class MyComponent {
// Before
onClick = (text) => {};
// After: lambda needs an annotation
onClick = (text: string) => {};

// Before
defaultProps = { foo: 3 };
// After: Literal assignment needs an annotation
defaultProps: { foo: number } = { foo: 3 }

// Before
render() {
return <div>Hi</div>;
}
// After: Method needs to be fully annotated
render(): React.Node {
return <div>Hi</div>;
}
}

Upgrading your own repos

We are also shipping a codemod in the Flow binary to help you upgrade your repos. You’ll want to run:

flow codemod annotate-functions-and-classes --write .

This codemod will only insert type annotations, so there should be no runtime changes. Still, you should check the final result before deploying your code to production.

--

--