Correct way to type nullable state when using React's useState hook
Solution 1
Currently, the TypeScript compiler thinks the type of email
and password
are null
(and no other value). You can resolve this by providing an explicit type parameter to the useState
call so that the types of email
and password
are known to be string
or null
.
const { useState } = React;
function Example() {
const [state, setState] = useState<{email: null | string, password: null | string}>({ email: null, password: null });
function setEmail(email: string) {
setState(prevState => ({ ...prevState, email }))
}
return <p>{state.email}</p>
}
Solution 2
This is addressed in a few spots already:
https://dev.to/busypeoples/notes-on-typescript-react-hooks-28j2
https://codewithstyle.info/Using-React-useState-hook-with-TypeScript/
TLDR: pass a type argument to setState when you have an empty initial state
eg:
const [email, setEmail] = useState<string>();

Comments
-
Ilja 5 months
I am having trouble figuring out how to type
useState
function since it returns a tuple. In essence, I have to providenull
as initial value foremail
i.e. lets assume I can't use empty string here.I then have
setEmail
function to update this state value, which takes in email as string.ideally I would like to type my
useState
so it expects email to be either string or null if possible. At the moment it inherits it as onlynull
import * as React from "react"; const { useState } = React; function Example() { const [state, setState] = useState({ email: null, password: null }); function setEmail(email: string) { setState(prevState => ({ ...prevState, email })) } return <p>{state.email}</p> }
Following error is returned for
setEmail
function sincestring
in function argument is not valid type fornull
specified inuseState()
[ts] Argument of type '(prevState: { email: null; password: null; }) => { email: string; password: null; }' is not assignable to parameter of type 'SetStateAction<{ email: null; password: null; }>'. Type '(prevState: { email: null; password: null; }) => { email: string; password: null; }' is not assignable to type '(prevState: { email: null; password: null; }) => { email: null; password: null; }'. Type '{ email: string; password: null; }' is not assignable to type '{ email: null; password: null; }'. Types of property 'email' are incompatible. Type 'string' is not assignable to type 'null'. [2345] (parameter) prevState: { email: null; password: null; }
-
SgtPooki over 3 yearsI think you should comment/edit the accepted answer as your answer is not as readable and provides no additional benefits to the existing answer.
-
Admin over 3 yearsI think this solution is better considering it use less caracters : repeat
null | xxx
four times doesn't improve readability ? -
Nurbol Alpysbayev almost 3 yearsHaving
null
properties and not having them at all is not the same. -
tjeisenschenk about 2 yearsUsing a Partial is actually a good idea and helped me :)
-
refaelio almost 2 yearswhat about objects?
-
wongz about 1 year@refaelio Even for objects, if you keep the brackets empty it won't cause issue if you have a defined interface or type. For example, this works
const [user, setUser] = useState<UserType>();
whereas this does not workconst [user, setUser] = useState<UserType>(null);