Say I have a parent component with two child components:
const Parent = () => {
   const [myVar, setmyVar] = useState(false)
   return (
     <>
       <MyChildComponent1 myVar={myVar} setMyVar={setMyVar} \> 
       <MyChildComponent2 myVar={myVar} \>
     </>
   )
}
Now how would I go about setting the type correctly in MyChildComponent2?
This is what I've come up with so far:
const MyChildComponent1 = (
  {myVar, setMyVar}: 
  {myVar: boolean, setMyVar: (value: boolean) => void}) = (...)
Is the type for setMyvar correct? Or should it be something else?
To pass an object as props to a component in React TypeScript: Define an interface for the type of the object. Pass an object of the specified type to the child component, e.g. <Employee {... obj} /> .
To type the useState hook as an object in React, use the hook's generic, e.g. const [employee, setEmployee] = useState<{name: string; salary: number}>({name: '',salary: 0}) . The state variable will only accept key-value pairs of the specified type.
The type that would match the function returned from invoking useState would be:
setMyVar: (value: boolean | ((prevVar: boolean) => boolean)) => void;
If we look at the type definition file from DefinitelyTyped [1], we can see that the second type in the return type is a dispatch:
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
Thus the generic type provided is passed through to SetStateAction<S>, which is defined as:
type SetStateAction<S> = S | ((prevState: S) => S);
So essentially, an interface for your component would be the following:
interface IProps {
  myVar: boolean;
  setMyVar?: (value: boolean | (prevVar: boolean) => boolean) => void;
}
As @Retsam said, it's best to use React's exported types:
import { Dispatch, SetStateAction } from "react";
interface IProps {
  myVar: boolean;
  setMyVar?: Dispatch<SetStateAction<boolean>>;
}
References: [1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L845
As @Retsam mentioned, you can also import and use the types Dispatch and SetStateAction from React:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
  myVar: boolean,
  setMyVar: Dispatch<SetStateAction<boolean>>
) => {...};
When I find myself frequently using this, I create a type alias to help with readability
import React, { Dispatch, SetStateAction } from 'react';
type Dispatcher<S> = Dispatch<SetStateAction<S>>;
const MyChildComponent1 = (
  myVar: boolean,
  setMyVar: Dispatcher<boolean>,
) => {...};
hope this helps.
Adding onto @fiz's comment, his code of block was slightly not working for me:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
  myVar: boolean,
  setMyVar: Dispatch<SetStateAction<<boolean>>
) => {...};
I had to set setMyVar: Dispatch<SetStateAction<boolean>> (there was one too many brackets)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With