- React Typescript — useState hook
- React Typescript useState hook with primitive types
- React typescript useState object example
- React typescript useState Array of objects.
- How to use React useState hook with Typescript
- Initializing useState using typescript type inference #
- What is type inference? #
- What’s the problem when using type inference for useState ? #
- How to explicitly set the useState type using generics? #
- Explicitly setting types for simple values
- Explicitly setting types for complex objects
- How to initialize useState for array of objects. #
- When do you need use generics for useState ? #
- Is it possible to use for useState type? #
- Why do you need to properly set the type for useState ? #
- Conclusion #
- Resources #
- The React TypeScript Cheatsheet – How To Set Up Types on Hooks
- Set types on useState
- Set types on useRef
- Set types on useContext
- Set types on useReducer
- Set types on useMemo
- Set types on useCallback
React Typescript — useState hook
Learn set variable type in useState hook of react typescript, an array of objects primitive types interface type aliases..
React hooks are new features introduced in React Typescript. This tutorial explains about useState hook in React Typescript.
useState hook used to store data in the typescript react component.
Typescript is a typed language, and every value must be declared with type.
So data stored in State must be declared with type explicitly.
Here is a syntax for useState hook
- numbers with zero
- String with «»
- boolean with false
- Array with []
- Objects with an empty object with property values have defaulted.
setProperty with type allows you to accept declared types and avoid runtime errors.
React Typescript useState hook with primitive types
Following are different primitive data types with the useState hook can also be defined with type inference
type is inferred from the default value.
Here, the loading value is inferred as a boolean type, isLoading function takes a boolean value
Here are String and number types
(5000) const [name, setName] = useState("john")
Here is an example to set the string in the useState React hook example.
from 'react'; interface Student < name: string ; marks: number ; >function UseStateExample()< const [message, setMessage] = useState("") // type is string const updateMessage=()=> < setMessage("w3schoolsio") >return ( <> Welcome - >); >; export default UseStateExample;
React typescript useState object example
- Created an interface type for holding the object.
- useState used with type, setting the state accepts object type only
- Default value in the state is assigned with an empty object with default property values.
from 'react'; interface Student < id: number; name: string; >; function UseStateExample()< const [student, setStudent] = useState(); useEffect(() => < setStudent(< id:11, name : "john", >); >, []); return ( <> Welcome
id: - name: >); >; export default UseStateExample;
React typescript useState Array of objects.
- Initial value in useState in one of the following An initialized array of objects with square brackets[].
Another way, State accepts an array of generic types.
from 'react'; interface User < id: number; name: string; >; function UsersComponent()< const [users, setUsers] = useState([]); const addUser=()=> < setUsers(prevUsers =>[ . prevUsers, , ]) > return ( <> Welcome
Listof Users
< return ( > id: - name: ); >)> >); >; export default UsersComponent; How to use React useState hook with Typescript
Hello! Let us explore how to use React useState hook with typescript and avoid any compile time errors. We will try to explore different scenarios when initializing useState, what are the best practices, and bad practices as well, all complete in one full guide! Let’s go!
Initializing useState using typescript type inference #
When we use typescript along with our react application, don’t have to make any changes if the state is immediately initialized upon declaration. For example:
import React, < useState >from "react"; const ComponentA = () => < const [count, setCount] = useState(0); return ; >; export default ComponentA;123456789 Since we initialized useState as 0 , the typescript engine in our vscode editor automatically infers that count is of type number . This is works for any type in our react application
What is type inference? #
While typescript is a type language, it is not mandatory to specify the type for every variable. Type inference is when typescript infers/predicts the type of certain variables based on its initialization when no explicit information is available.
let x = 5 //x is a number let greeting = "hello" //greeting is a string; x = greeting // Compiler Error: Type 'string' is not assignable to type 'number'
12345
What’s the problem when using type inference for useState ? #
The problem with using type inference is when we initialize useState with incomplete data. This could be null, undefined or some object with incomplete data type.
Example when useState is initialized using null or undefined. It doesn’t know the type of data we want for count and state which produces an error.
import React, < useEffect, useState >from "react"; const ComponentA = () => < const [count, setCount] = useState(); const [state, setState] = useState(null); useEffect(() =>< setCount(count + 1); //error: Object is possibly 'undefined' setState("hello"); //error: Argument of type '"hello"' is not assignable to parameter of type 'SetStateAction' >, []); return ; >; export default ComponentA; 123456789101112131415 import React, < useEffect, useState >from 'react' const ComponentB = () => < const [user, setUser] = useState(< email: '', >) useEffect(() => < setUser(< email: "test@reacthustle.com", username: "foobar", //type error: Argument of type '< email: string; username: string; >' is not assignable to parameter of type 'SetStateAction>'. >); >, []) return ( ComponentB ) > export default ComponentB
12345678910111213141516171819202122
How to explicitly set the useState type using generics? #
If you already have knowledge about generics, you should know that all hooks in react have a generic version that allows us to specify the types. It’s like declaring what types of values can the setCount function accept or what types of values can the count variable give us.
Explicitly setting types for simple values
First we have to add a generic parameter after useState . This is like saying: I want to declare count as a number or undefined and I want setCount to only accept number or undefined values.
import React, < useEffect, useState >from "react"; const ComponentA = () => < const [count, setCount] = useState(); const [state, setState] = useState(null); useEffect(() => < setCount(count + 1); //error: Object is possibly 'undefined' setState("hello"); //error: Argument of type '"hello"' is not assignable to parameter of type 'SetStateAction' >, []); return ; >; export default ComponentA; 12345678910111213141516 If we hover over count, we can see that it is explicitly set to number, undefined is still included since we didn’t initialize it with a number value. As a result, setCount still has an error since we cannot add undefined to a number.
If we want to make sure that count is a number, we have to add guards to it before setting the value.
. if (typeof count === "number") < setCount(count + 1); >.
12345
Explicitly setting types for complex objects
To set the types for objects, first we have to declare a type or an interface and use that as the generic parameter for the useState hook.
import React, < useEffect, useState >from "react"; type User = < email: string; username?: string; >; // interface User < // email: string; // username?: string; // >; const ComponentB = () => < const [user, setUser] = useState(< email: "", >); useEffect(() => < //this works now setUser(< email: "test@reacthustle.com", username: "foobar", >); >, []); return ComponentB; >; export default ComponentB;
1234567891011121314151617181920212223242526272829
How to initialize useState for array of objects. #
If we rely on type inference for arrays, the typescript compiler wouldn’t know what types of array it will be and this will result in a type error. For example
import React, < useEffect, useState >from "react"; const ComponentB = () => < const [users, setUsers] = useState([]); //const users: never[] useEffect(() =>< //error: Type '< email: string; username: string; >' is not assignable to type 'never' setUsers([ < email: "test@reacthustle.com", username: "foobar", >, ]); >, []); return ComponentB; >; export default ComponentB;
12345678910111213141516171819
To fix this, we have to once again use the generic parameter for useState to let typescript know that this is an array of users.
import React, < useEffect, useState >from "react"; //create a type that we're expecting type User = < email: string; username?: string; >; . const [users, setUsers] = useState([]); //const users: User[] . or const [users, setUsers] = useState>([]);
12345678910111213
When do you need use generics for useState ? #
The best practice is to explicitly set the type using generic parameter if you don’t know the type before initialization. For example, when fetching data from the backend, you can’t rely on type inference if you don’t have the values at compile time.
import React, < useEffect, useState >from "react"; //declare a type for the expected response from the backend. type User = < email: string; username?: string; >; const ComponentB = () => < const [users, setUsers] = useState>([]); //const users: User[] useEffect(() => < fetch("https://jsonplaceholder.typicode.com/users").then(async (res) => < if (res.status == 200) < const _users = (await res.json()) as User[]; setUsers(_users); // no error >>); >, []); return ; >; export default ComponentB;
12345678910111213141516171819202122232425
Is it possible to use for useState type? #
While it definitely is possible to use , it would defeat the purpose of using typescript since we lose all the development experience it provides.
import React, < useEffect, useState >from "react"; const ComponentB = () => < const [users, setUsers] = useState([]); //const users: any[] useEffect(() => < fetch("https://jsonplaceholder.typicode.com/users").then(async (res) => < if (res.status == 200) < const _users = await res.json(); setUsers(_users); // no error >>); >, []); return ( < return > ; // There's no type error here. We would only see the bug when we run it. >)> ); >; export default ComponentB;
123456789101112131415161718192021222324
It won't be an awesome developer experience if we have to predict what the properties are for the user object.
While there are definitely scenarios where using makes sense (when you don't care about the object), it's best to avoid setting any as much as possible.
Why do you need to properly set the type for useState ? #
It provides us with type safety which is the reason why we're using typescript in the first place. This helps us a lot during development since it provides us with autocomplete/intellisense, as well as compile-time type checking to easily avoid compile-time errors.
Conclusion #
We learned on how to initialize useState with typescript using type inference and generics. We also learned to initialize different values such as primitive types (number, string,etc) , complex objects and arrays of objects. We also learned to avoid any as much as the type since it provide us with no benefits when using typescript.
Resources #
If you like tutorials like these, please leave a like or share this article! If you'd like to receive more tutorials directly to your inbox, subscribe to our newsletter !
The React TypeScript Cheatsheet – How To Set Up Types on Hooks
Ibrahima Ndaw
TypeScript lets you type-check your code in order to make it more robust and understandable.
In this guide, I will show you how to set up TypeScript types on React hooks (useState, useContext, useCallback, and so on).
Set types on useState
The useState hook allows you to manage state in your React app. It's the equivalent of this.state in a Class component.
import * as React from "react"; export const App: React.FC = () => < const [counter, setCounter] = React.useState(0) return ( Result: ); >
To set types on the useState hook, you need to pass into <> the type of the state. You can also use a union type like this if you don't have an initial state.
Set types on useRef
The useRef hook returns a mutable ref object that allows you to access DOM elements.
import * as React from "react"; export const App: React.FC = () => < const myRef = React.useRef(null) return ( > My title
); >
As you can see, the way useRef receives types is the same as the useState hook. You just have to pass it into the <> . And, if you have multiple type annotations, just use union type as I do here.
Set types on useContext
useContext is a hook that allows you to access and consume a given Context in a React app.
import * as React from "react"; interface IArticle < id: number title: string >const ArticleContext = React.createContext([]); const ArticleProvider: React.FC = (< children >) => < const [articles, setArticles] = React.useState([ < id: 1, title: "post 1" >, < id: 2, title: "post 2" >]); return ( >> ); > const ShowArticles: React.FC = () => < const < articles >= React.useContext(ArticleContext); return ( ( > ))> ); >; export const App: React.FC = () => < return ( My title
); >
Here, we start by creating the IArticle interface that is the type of our context.
Next, we use it on the createContext() method to create a new context, and then initialize it with [] . You can also use null as an initial state if you want.
With that in place, we can now handle the state of the context and set the type on useContext in order to expect an array of type IArticle as a value.
Set types on useReducer
The useReducer hook helps you manage more complex states. It's an alternative to useState - but keep in mind that they are different.
import * as React from "react"; enum ActionType < INCREMENT_COUNTER = "INCREMENT_COUNTER", DECREMENT_COUNTER = "DECREMENT_COUNTER" >interface IReducer < type: ActionType; count: number; >interface ICounter < result: number; >const initialState: ICounter = < result: 0 >; const countValue: number = 1; const reducer: React.Reducer = (state, action) => < switch (action.type) < case ActionType.INCREMENT_COUNTER: return < result: state.result + action.count >; case ActionType.DECREMENT_COUNTER: return < result: state.result - action.count >; default: return state; > >; export default function App() < const [state, dispatch] = React.useReducer( reducer, initialState ); return ( Result: ); >
Here, we start by declaring the action types that allow handling the counter. Next, we set two types for the reducer function and the counter state, respectively.
The reducer expects a state of type ICounter and an action of type IReducer . With that, the counter can now be handled.
The useReducer hook receives the reducer function and an initial state as arguments and returns two elements: the state of the counter and the dispatch action.
To set the type for the values returned by ueReducer , just pass into the <> the type of your data.
With that in place, the counter can now be incremented or decremented through useReducer .
Set types on useMemo
The useMemo hook allows you to memoize the output of a given function. It returns a memoized value.
const memoizedValue = React.useMemo(() => < computeExpensiveValue(a, b) >, [a, b])
To set types on useMemo , just pass into the <> the type of data you want to memoize. Here, the hook expects a string as a returned value.
Set types on useCallback
The useCallback hook allows you to memoize a function to prevent unnecessary re-renders. It returns a memoized callback.
type CallbackType = (. args: string[]) => void const memoizedCallback = React.useCallback(() => < doSomething(a, b); >, [a, b]);
Here, we declare the CallbackType type that is using as type on the callback we want to memoize.
It expects to receive parameters of type string and should return a value of type void .
Next, we set that type on useCallback - and if you pass a wrong type to the callback or the array of dependencies, TypeScript will yell at you.
You can find other great content like this on my blog or follow me on Twitter to get notified.