Typed useState with TypeScript
useState is a hook that helps us manage state in function-based components in a version of React coming soon. How do we use this with TypeScript though so that our state is strongly-typed? Let’s find out …
I walked though an example of useState a few weeks ago where the state was defined as follows with useState
hooks:
const [firstName, setFirstName] = useState("");
const [emailAddress, setEmailAddress] = useState("");
If we hover over the variables in VSCode, we see that they are correctly to typed to string
and the setter is typed to Dispatch<React.SetStateAction<string>>
.
So, TypeScript has nicely inferred the type from the default value we passed to useState
which was an empty string. However what about when the state isn’t a simple primitive type - what about something like below?
export interface ISignUpData {
firstName: string;
emailAddress: string;
}
Well, as long as we can provide a nice default then TypeScript can infer the type:
What about when we can’t provide a default for the type to be inferred from? For example, let’s say we have state to store the result of the sign up form submission that has the following type:
export interface ISubmitResult {
success: boolean;
message: string;
}
However, we want the default value for this state to be undefined
because the form hasn’t been submitted yet. As we expect, TypeScript doesn’t infer this type as we would want:
So, what can we do? Well useState
is actually a generic function that can have the type passed into it. Let’s give this a try:
Perfect!
Wrap up
So, TypeScript can cleverly infer the type for useState
in many cases which is great. When TypeScript can’t infer the type we can pass it in as the generic parameter.
Comments
Jean-Marie October 1, 2019
Thanks for the clear explanation!
My problem was the same with this code snippet:
const [wearablesList, setWearablesList] = useState([]);
useEffect(() => {
const fetchWearables = async () => {
const result = await getWearablesList();
setWearablesList(result);
};
fetchWearables();
}, []);
I solved the typing problem with:
interface Provider {
connected: boolean;
type: string;
}
const [wearablesList, setWearablesList] = useState<Provider[]>([]);
Jonathan Leack October 30, 2019
Thanks this saved me in a pinch!
If you to learn more about using TypeScript with React, you may find my course useful: