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!