ffxsam
ffxsam

Reputation: 27713

Proper Flow type for React render method?

I'm curious what the proper Flow annotation is for both render methods in React classes, and simple returns in stateless functions:

const UserProfilePage = () => {
  return <div className="container page">
    <UserProfileContainer />
  </div>
};

By setting the return type intentionally incorrect (to a number), I got this error:

  8:   return <div className="container page">
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ React element: `div`
  8:   return <div className="container page">
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ React$Element. This type is incompatible with the expected return type of
  7: const UserProfilePage = (): number => {
                                 ^^^^^^ number

So, changing the code to this seems to satisfy Flow:

const UserProfilePage = (): React$Element => {
  return <div className="container page">
    <UserProfileContainer />
  </div>
};

I'm wondering if this is correct, and if so, where is this documented?

Upvotes: 18

Views: 17464

Answers (2)

Rory O&#39;Kane
Rory O&#39;Kane

Reputation: 30388

According to Flow documentation: React: Type Reference, the correct type is React.Node:

import * as React from 'react';

class MyComponent extends React.Component<{}> {
  render(): React.Node {
    // ...
  }
}

This represents any node that can be rendered in a React application. React.Node can be undefined, null, a boolean, a number, a string, a React element, or an array of any of those types recursively.

If you need a return type for your component render() methods or you need a generic type for a children prop then you should use React.Node.

However, the examples in the documentation generally don’t write out the type of render() explicitly. They only write out React.Component and the type of the props, like this:

import * as React from 'react';

type Props = {
  foo: number,
  bar?: string,
};

class MyComponent extends React.Component<Props> {
  render() {
    return <div>{this.props.bar}</div>;
  }
}

This is because extending React.Component automatically tells Flow what the render() method should return.

Upvotes: 7

Nikita
Nikita

Reputation: 2943

You don't need to annotate the render method, Flow should be able to infer the output type because it knows what JSX desugars to.

Flow has a built-in React interface, where all this stuff is defined:

declare class React$Element<Config> {
  type: ReactClass<Config>;
  props: $PropsOf<Config>;
  key: ?string;
  ref: any;
}

And then

render(): ?React$Element<any>;

So if you want to provide an explicit return type of a render method, you can use that signature. Well, maybe without a question mark if know you're not returning null. Not sure if there's any effect to omitting <any>.

Upvotes: 29

Related Questions