How to type React.useState() which can get multiple types as its value with Typescript

Viewed 2075

I'm trying to type useState() hook which can get number and string type as its value.

export interface Select {
  selectValue: React.Dispatch<React.SetStateAction<number | string>>;
  ...
}

And I'm trying to use above component like this,

const [value, setValue] = React.useState(0);
<Select selectValue = {setValue} />

But It gives me this Error.

Type 'Dispatch<SetStateAction<number>>' is not assignable to type 'Dispatch<SetStateAction<string | number>>'.
  Type 'SetStateAction<string | number>' is not assignable to type 'SetStateAction<number>'.
    Type 'string' is not assignable to type 'SetStateAction<number>'.

How can I resolve this Error?

3 Answers

You just need to provide a generic type argument to useState<T> like this:

const [value, setValue] = useState<string | number>(0);

Otherwise, it will infer the type from your initial value 0 which is only number. Here's a complete example:

TS Playground link

import {
  default as React,
  Dispatch,
  ReactElement,
  SetStateAction,
  useState,
} from 'react';

interface SelectProps {
  selectValue: string | number;
  setSelectValue: Dispatch<SetStateAction<string | number>>;
}

declare function Select (props: SelectProps): ReactElement;

function Example (): ReactElement {
  const [value, setValue] = useState<string | number>(0);
  return <Select selectValue={value} setSelectValue={setValue} />;
}

Break it down so its like this:

export interface Select {
  selectValue: React.Dispatch<React.SetStateAction<number>> | React.Dispatch<React.SetStateAction<string>>;
  ...
}

Also why are you passing the setValue, did you mean to pass the value itself? (<Select selectValue = {value} />)

You might need to check what the <Select> component's selectValue callback passes in the arguments. It might not be passing a number that is expected in the setValue method.

Related