'Typescript useState: SetState in Child with argument

thx for any help.

How can I pass down setState to a child component and use the c argument without a typescript error?

Parent: Passing down setState

export interface State {
    value1: string;
    value2: string;
}

const Parent = () => {
    const [state, setState] = useState<State>({
        value1: "test",
        value2: "test",
    });

    return (
        <React.Fragment>
            <Child setState={setState} />
        </React.Fragment>
    );
};

export default Parent;

Child: use setState with c as argument, c is read underlined with a type error

type Props = {
    setState: Dispatch<State>;
};

const Child: React.FC<Props> = ({ setState }) => {
    return (
        <React.Fragment>
            <button
                onClick={() => {
                    //c is read underlined: Argument of type '(c: any) => any' is not assignable 
                    //to parameter of type 'State'.
                    //Type '(c: any) => any' is missing the following properties from type 
                    //'State': value1, value2
                    setState((c) => {
                        return {
                            ...c,
                            value2: "HelloWorld",
                        };
                    });
                }}
            />
        </React.Fragment>
    );
};

export default Child;


Solution 1:[1]

try this

type Props = {
    setState: React.Dispatch<React.SetStateAction<any>>;
};

Solution 2:[2]

To start with, since you're using functional components, you should separate state into separate variables, rather than have a single state object. Rather than { value1: string; value2: string; }, make two separate calls to useState. This will simplify logic later.

const Parent = () => {
    const [value1, setValue1] = useState('test');
    const [value2, setValue2] = useState('test');

    return (
        <React.Fragment>
            <Child setValue2={setValue2} />
        </React.Fragment>
    );
};

(Note that Parent doesn't need a separate type declaration for State, since it can be inferred automatically)

The key is to type the setValue2 prop in the child properly. If you hover over the setValue2 in the parent, you'll see that its type is:

React.Dispatch<React.SetStateAction<string>>

So that's what you need the Child to have for it:

const Child = ({ setValue2 }: { setValue2: React.Dispatch<React.SetStateAction<string>> }) => {
    return (
        <React.Fragment>
            <button
                onClick={() => {
                    setValue2('HelloWorld');
                }}
            />
        </React.Fragment>
    );
};

Solution 3:[3]

This

type ChildrenProps = {
  setState: (value: State) => void
}

Or more prefered by me:

interface ChildrenProps {
  setState: (value: State) => void
}

Most accurate, but impossible to remember:

import { Dispatch, SetStateAction} from "react"

interface ChildrenProps {
  setState: Dispatch<SetStateAction<string>>
}

If you hover over your setState function of your parent component, you will see a type like this Dispatch<SetStateAction<string>> which you can use just like in Drew Cordanos answer. For me that type is hard to remember. Luckily typescript is clever and also accepts a simplified form: (value: State) => void

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Cordano
Solution 2
Solution 3 Jingyi Wang