Suggest an editImprove this articleRefine the answer for “How do you type state with useState()?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**useState()** usually infers the type automatically from the initial value (`useState(0)` gives `number`). **Key point:** you need to specify the type explicitly via the `<T>` generic when the initial value is `null`/`undefined`, or when you need unions, objects, or arrays.Shown above the full answer for quick recall.Answer (EN)Image## Basic cases ```javascript // Type inferred from the literal const [count, setCount] = useState(0); // number const [title, setTitle] = useState("Hello"); // string const [open, setOpen] = useState(false); // boolean ``` When **you need to specify the type explicitly**: - the initial value is null / undefined; - complex unions, objects, arrays; - you want to narrow the type (for example, literal types). ```javascript // Explicit typing with null const [user, setUser] = useState<User | null>(null); // Union type Status = "idle" | "loading" | "success" | "error"; const [status, setStatus] = useState<Status>("idle"); // Literal variants const [variant, setVariant] = useState<"primary" | "ghost">("primary"); ``` --- ## Objects and partial updates ```javascript type Form = { name: string; age: number }; const [form, setForm] = useState<Form>({ name: "", age: 0 }); // Update based on the previous state setForm(prev => ({ ...prev, name: "Tim" })); ``` > Tips > • The type of prev is inferred automatically. > • For multi-step forms and complex logic, consider useReducer. --- ## Arrays and collections ```javascript const [items, setItems] = useState<string[]>([]); // Adding an item setItems(prev => [...prev, "new"]); // Set/Map (mutable!) - create new instances const [ids, setIds] = useState<Set<string>>(new Set()); setIds(prev => new Set(prev).add("42")); ``` --- ## Nullable / Optional done right ```javascript // Better: an explicit union with null const [el, setEl] = useState<HTMLDivElement | null>(null); // Same with undefined const [token, setToken] = useState<string | undefined>(undefined); ``` > Don't use "whatever works" via as any: it breaks TS's guarantees. --- ## Lazy initializer (for expensive computations) ```javascript const [big, setBig] = useState<number>(() => heavyCompute()); // The function runs once, on mount. ``` --- ## Derived types and "narrow" literals ```javascript // From API types type User = ApiUser & { fullName: string }; // A narrow literal via a const assertion const [align, setAlign] = useState<"left" | "center" | "right">("left"); // Or derive it from a settings object: const ALIGN = ["left", "center", "right"] as const; type Align = (typeof ALIGN)[number]; const [a, setA] = useState<Align>("left"); ``` --- ## Request state (discriminated unions) ```javascript type LoadState = | { status: "idle" } | { status: "loading" } | { status: "success"; data: Post[] } | { status: "error"; error: string }; const [state, setState] = useState<LoadState>({ status: "idle" }); setState({ status: "loading" }); // ... setState({ status: "success", data }); ``` > Convenient for exhaustive switch statements without a "default". --- ## Setter types and updater functions ```javascript const [n, setN] = useState(0); // Type: React.Dispatch<React.SetStateAction<number>> // You can pass a function that receives prev setN(prev => prev + 1); ``` --- ## Controlled inputs ```javascript const [value, setValue] = useState(""); const onChange = (e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value); ``` --- ## When to specify the generic explicitly Specify `<T>` if: - the initial value is null/undefined; - arrays/objects/unions; - you want to "lock in" an exact type (for example, string vs string | undefined). Quick examples: ```javascript // good const [data, setData] = useState<Post[] | null>(null); // good const [map, setMap] = useState<Map<string, number>>(new Map()); // good const [mode, setMode] = useState<"view" | "edit">("view"); // bad - too broad, any const [unknown, setUnknown] = useState<any>(null); ``` --- ## Common mistakes and how to avoid them - Initializing useState(null) without a type -> becomes null, and TS keeps complaining afterward. Fix: useState<User | null>(null) - Mutating complex structures (Set/Map, objects) -> React won't see the change. Fix: create a new structure. - State tied to many branches -> a tangled union. Fix: think about useReducer. --- ### Summary 1. Trust type inference, **but** specify `<T>` for null/undefined and complex shapes. 2. For objects and arrays: **immutable** updates. 3. For loading scenarios: **discriminated unions**. 4. Don't be afraid of the lazy initializer and literal types: they make state precise and reliable.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.