useState and Type Inference
On this page
Type Inference Basics
- TypeScript infers type from initial value.
- Primitive initialization is usually safe without generics.
- Nullable or async state requires explicit unions.
Example: Primitive State
const [count, setCount] = React.useState(0); // inferred as number
Example: Nullable State
type User = { id: string; name: string };
const [user, setUser] = React.useState<User | null>(null);
Avoid Type Widening
- Do not initialize with empty object when a specific shape is expected.
- Avoid casting as unknown as T to silence errors.
- Model async states explicitly instead of using multiple booleans.
Discriminated Union Pattern
type ViewState =
| { status: "loading" }
| { status: "error"; message: string }
| { status: "ready"; data: User[] };
const [state, setState] = React.useState<ViewState>({ status: "loading" });
Failure Modes
- Empty object initialization forcing unsafe casts later.
- Multiple boolean flags creating impossible state combinations.
- Null not included in union causing runtime access errors.
- Over broad types hiding invalid UI states.
Operational Checklist
- Async state uses union modeling.
- No unsafe type assertions in state updates.
- Derived values computed, not stored.
- State models represent valid UI transitions only.