Lesson 10 · Module 1.5 — Core type vocabulary

Tuples vs arrays — and why a parameter list is a tuple

There’s a sharp line worth drawing: string[] is a homogeneous, any-length array, while [string, number] is a fixed-length, positional tuple. The same square brackets, two very different contracts. Once you see it, advanced generics over function parameters stop looking alien.

Array T[] — same type, any length

type Names = string[];
const names: Names = ["Alice", "Bob", "Charlie"];  // any number of strings
names[0];    // string
names[100];  // string (TS assumes the element type at every index)

Read string[] as “a list of strings — could be 0, 3, or 300 of them.” Every position has the same type, and the length is open.

Tuple [A, B, C] — fixed length, type per position

type PersonTuple = [string, number, boolean];
const person: PersonTuple = ["Alice", 25, true];  // exactly 3 elements
person[0];  // string
person[1];  // number
person[2];  // boolean
person[3];  // ERROR — the tuple only has 3 elements

Read [string, number, boolean] as “exactly three slots: a string, then a number, then a boolean.” The order and the count are part of the type. That is the whole distinction:

array T[]tuple [A, B]
lengthvariable / openfixed
element typesall the sameone per position
position matters?noyes

Why a parameter list is a tuple

Here is the payoff this idea builds toward. A function’s parameters have different types at fixed positions in a fixed order — which is exactly a tuple. So when a generic captures “all the arguments,” it captures them as a tuple, not an array:

const updateUser = (id: number, name: string, email: string) => {};

// ❌ Array approach — loses type safety:
type ArrayApproach = (...args: any[]) => void;   // can't tell positions apart, all info lost

// ✅ Tuple approach — preserves type safety:
type TupleApproach = (...args: [number, string, string]) => void;
//                              └ exact types at exact positions ┘

Read ...args: [number, string, string] as “the rest-spread of a tuple” — it’s just (id: number, name: string, email: string) written as one positional type. This is why library types you’ll meet later say ...args: TArgs with TArgs extends any[]: TArgs is really a tuple of the parameter types, captured so each position keeps its own type. An any[] would flatten them all to one type and throw the positions away.

Read it this way

Brackets with one element type and a trailing []array (homogeneous, open length). Brackets listing several types in order → tuple (positional, fixed length). A ...rest of a tuple is a parameter list.

Check yourself

Recall, don’t re-read. (Answers reveal on click.)

How do string[] and [string] differ?
Why are function parameter lists modeled as tuples rather than arrays?
For person: [string, number, boolean], what does person[3] give?

Primary source

The handbook section is Object Types — Tuple Types (arrays are covered just above, under Array Types). Best way to feel it: paste the PersonTuple block into the TS Playground, then try adding a 4th element and read the error.

Try it yourself

See a [...] and unsure if it’s a tuple or an array? Check whether it lists one element type with a trailing [], or several types in order. Next lesson (1.6): the never type — its two faces in exhaustive switches and in mapped types.