The first version of Flow support for React was a magical implementation of React.createClass() . Since then, React has evolved significantly. It is time to rethink how Flow models React.

In Flow 0.53.0 we are changing how Flow models React and in doing this we can provide better types for higher-order components, strict typing for React children, and fixes for a host of bugs in Flow’s React support.

The biggest change we are making is to modify how you define React class components. From version 0.53.0 and on, the React.Component class will take two type arguments, Props and State (as opposed to the three type arguments including DefaultProps that React.Component took before). In the past Flow would infer Props and State from your property definitions, but now Flow expects you to pass in Props and State explicitly. A React component in 0.53.0 looks like this:

type Props = {

foo: number,

}; type State = {

bar: number,

}; class MyComponent extends React.Component<Props, State> {

state = {

bar: 42,

};



render() {

return this.props.foo + this.state.bar;

}

}

When your component has no state, you only need to pass in a single type argument. The second type argument that represents state will default to undefined. Without state your component definition would look like this:

type Props = {

foo: number,

}; class MyComponent extends React.Component<Props> {

render() {

return this.props.foo;

}

}

If your component has default props then add a static defaultProps property:

type Props = {

foo: number,

}; class MyComponent extends React.Component<Props> {

static defaultProps = {

foo: 42,

}; render() {

return this.props.foo;

}

}

Flow will infer the type of default props from your static property. You don’t need to provide Flow with any type annotations for default props. The same thing will work for functional components:

function MyComponent({ foo }: { foo: number }) {

return foo;

} MyComponent.defaultProps = {

foo: 42,

};

You will notice that the components in our examples have been returning numbers from their render methods. This is because Flow’s React types have been updated for React 16. Flow will now let you return strings, arrays, and of course numbers from render methods. Once React 16 is released, React will render those values.

Later in this article I’ll discuss why we are no longer inferring the types of props and state. In short, it was confusing to teach and could be bad for performance.

We will also be providing simple-to-run codemods with the flow-upgrade utility, which I’ll also discuss later in the article.

For now let’s move on and talk about what else we are including in Flow 0.53.0 for React.

Strict Typing for React Children

As the React community has evolved, we have seen some incredibly creative use cases for React children. For example, the React Native <View> component does not allow string children, the React Native <TabBarIOS> component only allows for <TabBarIOS.Item> children, and React Router 4 includes an API that wants a function for children which looks like this:

<Route path={to}>

{({ match }) => (

<li className={match ? 'active' : ''}>

<Link to={to} {...rest} />

</li>

)}

</Route>

Now Flow will be able to type these children based APIs to ensure safety in your React code. For the React Router example above, you would type the <Route> component’s children as:

type Props = {

children: (data: { match: boolean }) => React.Node,

path: string,

}; class Route extends React.Component<Props> { /* ... */ }

To learn more about typing React children read our documentation guide on the topic.

The children prop returns a React.Node , which is the type for any value that can be rendered by React. This also brings us to the next feature we are adding to Flow’s React support…

New Utility Types to Model Advanced Patterns

Modeling advanced React patterns, like higher-order components, is difficult today because the types you would need are either not provided or undocumented. In this release we added a whole suite of utility types which are all documented on our website. Some of the highlights include:

React.Node , which we were introduced to earlier, represents any value which can be rendered by React. It is the type of the children for JSX intrinsic elements like <div> and it is also the type that is returned from React.Component render methods and stateless functional components. A React.Node could be a string, number, boolean, null, React element, or an array of any of those values.

, which we were introduced to earlier, represents any value which can be rendered by React. It is the type of the children for JSX intrinsic elements like and it is also the type that is returned from render methods and stateless functional components. A could be a string, number, boolean, null, React element, or an array of any of those values. React.ComponentType<Props> is is the type of any class component or stateless function component that expects props with the type Props . This type is incredibly useful as the input type for higher order components or any operation which needs to take a variable component type.

is is the type of any class component or stateless function component that expects props with the type . This type is incredibly useful as the input type for higher order components or any operation which needs to take a variable component type. React.ChildrenArray<T> is the type for the React children data structure. React children are not a simple array: they could be a single value or an arbitrarily nested array. React.ChildrenArray<T> allows you to model the data structure and cleanly interoperate with the React.Children API, which is typed in Flow 0.53.0.

is the type for the React children data structure. React children are not a simple array: they could be a single value or an arbitrarily nested array. allows you to model the data structure and cleanly interoperate with the API, which is typed in Flow 0.53.0. React.Element<Type> is not a new type, but it has a new API! In the past you would pass the type of the element’s props to React.Element . For example: React.Element<MyComponentProps> . However, this makes a lot less sense than passing in the component directly such as in: React.Element<’div’> or React.Element<typeof MyComponent> . (The typeof is important!) We’ve changed the React.Element<Type> API so that it takes the type of your component instead of the type of your component’s props.

These are some of the highlights, but there are many more utility types that you can read about in our documentation.

Typing Higher-order Components

Now that we have these utility types, it is much easier to type a higher-order component. We have a full documentation guide on our website that will teach you how to type higher-order components, but let’s run through a quick example here. Often a higher-order component will “inject” a prop stored in context. react-redux does this with the connect() function. Here is how you would type a simple higher-order component that injects a number prop, foo :

function injectProp<Props: {}>(

Component: React.ComponentType<{ foo: number } & Props>,

): React.ComponentType<Props> {

return function WrapperComponent(props: Props) {

return <Component {...props} foo={42} />;

};

} class MyComponent extends React.Component<{

a: number,

b: number,

foo: number,

}> {} const MyEnhancedComponent = injectProp(MyComponent); // We don't need to pass in `foo` even though

// `MyComponent` requires it!

<MyEnhancedComponent a={1} b={2} />;

Here we use the new React.ComponentType<Props> utility along with an intersection to inject the prop foo .

Even More

There is a lot more that we fit into this release for our React support. If we missed anything in improving our React support let us know.

Correct types for the class component setState() updater function.

updater function. Correct types for React ref functions.

Allow JSX class components to use exact object types as their props.

Fix member expressions when creating JSX components. Like in: <TabBarIOS.Item> .

. Fix for multiple spreads in a JSX element.

Fix that sometimes allowed undefined values for a prop even if the prop was required.

Improved types for React.cloneElement() and React.createFactory() .

and . Additions for the React.ElementProps<Type> and React.ElementRef<Type> utility types.

and utility types. Add a type argument to SyntheticEvent s and correctly typed currentTarget using that type argument.

s and correctly typed using that type argument. Conversion for the React type definitions from a CommonJS to an ES module.

Because we fixed a lot of bugs, Flow will likely catch a lot more errors than it did before in your React code. If you see a lot of errors it’s because Flow got a lot better at checking React!

As you may have noticed we also made a couple of breaking changes which is also why we are announcing…

flow-upgrade

flow-upgrade is a utility to make upgrading when there are breaking changes in Flow much less painful. flow-upgrade is the exact same tool we use to upgrade our code internally at Facebook and it is available as an npm module that anyone can use.

You can run flow-upgrade with the yarn create feature:

yarn create flow-upgrade

…or if you could use npx :

npx flow-upgrade

If you have any trouble upgrading, let us know by sending us a message on Twitter: flowtype.