type User = { id: string; name: string };
const [count, setCount] = useState(0); // number, inferred
const [user, setUser] = useState<User | null>(null); // explicit
const inputRef = useRef<HTMLInputElement>(null);
// later
inputRef.current?.focus();
<input ref={inputRef} />
Let useState infer simple types, and pass a generic when the start value is narrower, like useState<User | null>(null). For a DOM ref, write useRef<HTMLInputElement>(null).
useState infers its type from the initial value. So useState(0) is number and needs no annotation. Sometimes the initial value does not represent all future values. Then pass the type explicitly.
useState(null)would be typed as justnull. SosetUser(user)would fail.useState<User | null>(null)fixes that. You then narrowuserbefore you use it.
useRef for a DOM element: pass the element type and null, as in useRef<HTMLInputElement>(null). React sets current after the component mounts. current is typed as possibly null, so use optional chaining (?.) or a check. In the React 19 types, useRef requires an initial argument.
useRef for a value: a ref can also store a value that changes without re-rendering, such as a timer id. Give it the value type and an initial value.
useStateinfers its type from the initial value.- Pass a generic when the initial value is narrower than later values, like
User | null. - Use
useRef<HTMLInputElement>(null)for DOM refs. ref.currentmay benull, so check it or use?..- The React 19 types require an argument to
useRef.