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 monthsI am having trouble figuring out how to type
useStatefunction since it returns a tuple. In essence, I have to providenullas initial value foremaili.e. lets assume I can't use empty string here.I then have
setEmailfunction to update this state value, which takes in email as string.ideally I would like to type my
useStateso it expects email to be either string or null if possible. At the moment it inherits it as onlynullimport * 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
setEmailfunction sincestringin function argument is not valid type fornullspecified 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 : repeatnull | xxxfour times doesn't improve readability ? -
Nurbol Alpysbayev almost 3 yearsHavingnullproperties 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 worksconst [user, setUser] = useState<UserType>();whereas this does not workconst [user, setUser] = useState<UserType>(null);