Passing useState as props in typescript
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)
Dispatch & SetStateAction types
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>>
) => {...};
Bonus
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.
It can also be done like this using Interface and React components.
MainComponent.tsx
Value assignment of the useState component defined in Main is done in the child component. When this field is triggered, the code in useEffect will run.
import React, { useEffect } from 'react';
import Login from './views/Login/index';
const App: React.FunctionComponent = () => {
const [isAuthenticated, setAuthenticatedStatus] = React.useState(false);
useEffect(() => {
if (isAuthenticated)
window.location.href = "<redirect url>";
}, [isAuthenticated]);
return (<Login setLoginStatus={setAuthenticatedStatus} />)
};
export default App;
ChildComponent.tsx
import { Dispatch, SetStateAction, FunctionComponent } from 'react';
import authService from '../../apiServices/authService';
interface IProps {
setLoginStatus: Dispatch<SetStateAction<boolean>>;
}
const Login: FunctionComponent<IProps> = (props: IProps) => {
const login = async (username: string, password: string) => {
const response = await authService.authenticateUser(username, password);
if (response && response.statusCode == 200 && response.result.accessToken) {
props.setLoginStatus(true);
}
else {
// ...
}
};
return (
<>
...
</>
);
};
export default Login;
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