timothym
timothym

Reputation: 3275

How to do flow type annotations for React hooks (useState, etc.)?

How should we be using Flow type annotations with react hooks, such as useState? I've tried searching for some examples of how they should be implemented, but can't find anything.

I tried this:

const [allResultsVisible, setAllResultsVisible]: [ boolean, (boolean) => void, ] = useState(false);

Which doesn't throw any flow related errors, but I'm not sure if this is correct or the best way to annotate the hook. If my attempt isn't correct or the best way, what should I do instead?

Upvotes: 18

Views: 14758

Answers (4)

Vlad R
Vlad R

Reputation: 2624

In addition to the answers above,

Make sure you put // @flow at the very top of your file, to make all flow features working fine.

The only one solution which worked for me without putting // @flow at the top was:

const [allResultsVisible, setAllResultsVisible]: [ boolean, Function ] = useState(false);

Upvotes: 0

Archinowsk
Archinowsk

Reputation: 71

Type inferring doesn't work for me:

const [loading, setLoading] = React.useState(true) // boolean
setLoading('foo') // no Flow error
setLoading(1) // no Flow error

Had to add typings manually:

const [loading, setLoading]: [boolean, ((boolean => boolean) | boolean) => void] = React.useState(false)
setLoading('foo') // Flow error
setLoading(1) // Flow error

I have:

"react": "16.8.6",
"flow-bin": "0.100.0",

UPDATE

As @AndrewSouthpaw pointed, loading has to be used in some context or setLoading won't work correctly.

This works:

const [loading, setLoading] = React.useState(true);
(loading: boolean);

setLoading('foo'); // Flow error

The same without semicolons:

 const [loading, setLoading] = React.useState(true)
 ;(loading: boolean)

 setLoading('foo') // Flow error

ESLint

ESLint no-unused-expressions will give an error from this. eslint-plugin-flowtype has fixed version flowtype/no-unused-expressions.

Upvotes: 3

Cat Chen
Cat Chen

Reputation: 2416

If the type can be inferred from the initial value, no need to add typing information for Flow, for example:

const [open, setOpen] = React.useState(false);

If it can't be inferred because the initial value is a complex object, use generics to assign a type, for example:

type Merchandize = {|
  name: string,
  value: number,
|};

const [shoppingCare, setShoppingCart] = React.useState<Array<Merchandize>>([]);

Upvotes: 3

Andrew Smith
Andrew Smith

Reputation: 1444

Flow infers the types, as shown in the PR that added support for hooks to the Flow library.

UPDATE

As discussed in my comments of another answer, the resulting variables must be used contextually for the type-checking to work as expected.

const [loading, setLoading] = React.useState(true);
(loading: boolean);

setLoading('foo') // Flow error

vs.

const [loading, setLoading] = React.useState(true);

setLoading('foo') // no Flow error

Upvotes: 15

Related Questions