Tuples

A tuple is an array with a fixed number of elements where each position has its own type. It's the right tool when position carries meaning — a coordinate pair, a key and its value, or a function that returns two things at once.

Declaring a tuple

TS tuple.ts
let point: [number, number] = [10, 20];
let entry: [string, number] = ["apples", 5];

point = [10, 20, 30];
entry = [5, "apples"];
tsc output
error TS2322: Type '[number, number, number]' is not assignable to type '[number, number]'.
error TS2322: Type 'number' is not assignable to type 'string'.

[string, number] means exactly two elements: a string, then a number. Both the count and the order are checked, unlike (string | number)[] where any element may be either type and there can be any number of them.

Destructuring tuples

Tuples pair naturally with array destructuring, which gives each position a name:

TS destructure.ts
function minMax(values: number[]): [number, number] {
  return [Math.min(...values), Math.max(...values)];
}

const [low, high] = minMax([7, 2, 9, 4]);
console.log(`range: ${low}–${high}`);
Output
range: 2–9

This is the same pattern React's useState uses: it returns a [value, setter] tuple so you can name both pieces whatever you like.

Named (labelled) tuple elements

Labels make a tuple type self-documenting. They don't change how it behaves — they only show up in editor tooltips and error messages:

TS labelled.ts
type Range = [start: number, end: number];

function length([start, end]: Range): number {
  return end - start;
}

console.log(length([3, 10]));
Output
7

Optional and rest elements

A ? marks a trailing element as optional, and ... allows any number of elements of one type:

TS optional.ts
type RGB = [red: number, green: number, blue: number, alpha?: number];
type Command = [name: string, ...args: string[]];

const solid: RGB = [255, 128, 0];
const faded: RGB = [255, 128, 0, 0.5];
const cmd: Command = ["git", "commit", "-m", "init"];

console.log(solid.length, faded.length);
console.log(`${cmd[0]} has ${cmd.length - 1} args`);
Output
3 4
git has 3 args

Readonly tuples

A plain tuple can still be changed through array methods — the length guarantee is only checked when you assign a whole tuple. Marking it readonly blocks mutation entirely:

TS readonly-tuple.ts
const origin: readonly [number, number] = [0, 0];

origin[0] = 5;
tsc output
error TS2540: Cannot assign to '0' because it is a read-only property.

Writing as const after an array literal (lesson 14) produces a readonly tuple of literal types automatically: [0, 0] as const is typed readonly [0, 0].

When to use a tuple vs an object

Tuples are compact, but positions have no names at the use site — user[2] says nothing about what's stored there. A good rule: use a tuple for two or three closely related values that are usually destructured immediately; use an object with named properties for anything larger or longer-lived.

Try it yourself

Try it yourself
Console output
Note: at runtime a tuple is just an ordinary JavaScript array. Calling .push() on a non-readonly tuple compiles fine and quietly makes it longer than its type says — another reason to prefer readonly tuples when the shape matters.