Lesson 11 of 80
An array type that knows its exact length and the specific type of each position — turning `useState`'s [value, setter] return from a lucky guess into an actually-checked contract.
10 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
Why is useState's return type declared as a tuple rather than a plain array?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A plain Array<T> type only knows "a list of Ts" — nothing about how many there are, and every position has the same type. A tuple is more specific: a fixed length, with each position's type individually declared.
type Pair = [string, number];
const entry: Pair = ["age", 30]; // ✅
const bad: Pair = [30, "age"]; // ❌ wrong order
const short: Pair = ["age"]; // ❌ missing the second element
This is exactly what powers useState's familiar destructuring: useState<number>(0) returns [number, Dispatch<SetStateAction<number>>] — a tuple, not a plain array — which is precisely why const [count, setCount] = useState(0) gets count typed as number and setCount typed as a specific function, in that exact order, instead of both being some vague union.
let pair: [string, number] = ['age', 30] — fixed length, fixed order, each position has its own type.
[string, number?] (an optional second element) and [string, ...number[]] (a required first element followed by any number of numbers) — tuples aren't limited to purely fixed-length shapes.[name: string, age: number]) don't change the runtime behavior at all — they're purely a documentation/IDE-hint feature, improving autocomplete and error messages without adding any real constraint.Array.isArray(entry) is true, and nothing stops you from .push()-ing an extra element onto one at runtime — the fixed-length guarantee is a compile-time-only check, not an enforced runtime restriction."How does useState know that the first destructured value is the state and the second is the setter, with the right types for each?" is a great question to actually be able to answer — and tuples are the real mechanism, not something React does with special-case magic.