Skip to content

TypeScript - Tuples

Tuples are a special type in TypeScript that represent fixed-size arrays where the type of the element at each specific position (index) is known and fixed. Unlike regular arrays which usually contain elements of the same type and can grow or shrink, tuples define a precise structure for a small collection of related values.

Think of them as defining the types for each element in an array of a specific length.

Tuple types are declared using square brackets [] with the types listed in order.

let tupleName: [type1, type2, type3, ..., typeN];
// A tuple representing a key-value pair (string key, number value)
let keyValue: [string, number];
keyValue = ["userId", 12345]; // OK
// A tuple representing RGB color values
let rgbColor: [number, number, number];
rgbColor = [255, 0, 128]; // OK
// A mixed tuple
let personRecord: [string, number, boolean];
personRecord = ["Alice", 30, true]; // OK
// Incorrect assignments (wrong type or order)
// keyValue = [12345, "userId"]; // Error: Type 'number' is not assignable to type 'string'. Type 'string' is not assignable to type 'number'.
// rgbColor = [255, 0]; // Error: Type '[number, number]' is not assignable to type '[number, number, number]'. Source has 2 element(s) but target requires 3.
// personRecord = ["Bob", 40]; // Error: Type '[string, number]' is not assignable to type '[string, number, boolean]'.

Tuple elements are accessed using zero-based numerical indices, just like arrays. TypeScript provides type safety for each index.

let employee: [number, string, string] = [101, "John Doe", "Engineering"];
let employeeId: number = employee[0]; // Type is known to be number
let employeeName: string = employee[1]; // Type is known to be string
let department: string = employee[2]; // Type is known to be string
// let manager: string = employee[3]; // Error: Tuple type '[number, string, string]' of length '3' has no element at index '3'.
console.log(`ID: ${employeeId}`);
console.log(`Name: ${employeeName}`);
console.log(`Department: ${department}`);
// Modifying elements (respects the type at that index)
employee[2] = "Marketing";
// employee[0] = "E101"; // Error: Type 'string' is not assignable to type 'number'.

While tuples define a fixed structure at compile time, standard JavaScript array methods like push, pop, etc., can technically still be called on tuples at runtime. However, this should generally be avoided as it breaks the intended fixed-size, fixed-type-per-index nature of the tuple and TypeScript might not always catch type errors resulting from such modifications beyond the defined length.

It’s best practice to treat tuples as fixed-length structures after creation.

let myTuple: [string, number] = ["Count", 10];
// Updating elements is allowed and type-checked:
myTuple[1] = 20;
console.log(myTuple); // Output: [ 'Count', 20 ]
// Using push can bypass compile-time length checks (Use with caution!):
// myTuple.push(true); // Error in TS 4.0+: Argument type boolean not assignable to string | number
// In older TS versions or with less strict checks, this might compile,
// but `myTuple` no longer strictly matches the [string, number] shape.
// console.log(myTuple);
// pop() also works, but again modifies the tuple's structure
// let removed = myTuple.pop();
// console.log(removed);
// console.log(myTuple);

For immutability, consider using readonly tuples.

Make tuples immutable using the readonly keyword.

const readOnlyCoord: readonly [number, number] = [10, 5];
// readOnlyCoord[0] = 15; // Error: Index signature in type 'readonly [number, number]' only permits reading.
// readOnlyCoord.push(20); // Error: Property 'push' does not exist on type 'readonly [number, number]'.

Easily unpack tuple elements into individual variables, similar to array destructuring.

const httpStatus: [number, string] = [200, "OK"];
const [statusCode, statusMessage] = httpStatus;
console.log(`Status Code: ${statusCode}`); // Output: Status Code: 200
console.log(`Status Message: ${statusMessage}`); // Output: Status Message: OK
// Type checking applies during destructuring
// const [code, message, description]: [number, string, string] = httpStatus; // Error: Tuple type '[number, string]' of length '2' has no element at index '2'.

You can mark elements as optional using ?. Optional elements must appear at the end.

let optionalTuple: [string, number, boolean?];
optionalTuple = ["User", 1, true]; // OK
optionalTuple = ["Admin", 2]; // OK (optional element omitted)
console.log(optionalTuple[0]); // string
console.log(optionalTuple[1]); // number
console.log(optionalTuple[2]); // boolean | undefined

A tuple can have a rest element (...Type[]) at the end to represent an arbitrary number of trailing elements of a specific type.

// Must have at least a string and number, followed by any number of booleans
let mixedRestTuple: [string, number, ...boolean[]];
mixedRestTuple = ["Data", 100]; // OK
mixedRestTuple = ["Data", 100, true]; // OK
mixedRestTuple = ["Data", 100, true, false, true]; // OK
console.log(mixedRestTuple[0]); // string
console.log(mixedRestTuple[1]); // number
console.log(mixedRestTuple.slice(2)); // boolean[]

Tuples are useful when you need to return multiple values from a function or represent a small, fixed collection where the position of each element has a specific meaning and type.