DEV Community

Cover image for Using Tuples in TypeScript
Michael Mathews
Michael Mathews

Posted on

Using Tuples in TypeScript

In TypeScript, a tuple allows you to describe a structured array, where the position of each element is meaningful and dictates what type each is expected to be.

For example, you might use a tuple to store the data associated with a User type. You could declare this type mandating that the first value in a User tuple must be a number (representing the user's id), and the second a string (representing their displayName).

// Declaring a User type consisting of an array with
// a number at `[0]` followed by a string at `[1]`
type User = [number, string];

const Alice: User = [123, 'Alice']; // OK
const Bob: User = ['Bob']; // ERROR Type 'string' is not assignable to type 'number'.
Enter fullscreen mode Exit fullscreen mode

try in playground

You could make this more explicit by using named tuple elements in your type declaration. While the names make no functional difference, they will give you better hints in your IDE when you refer to an element in a tuple. For example, with named tuple elements, TypeScript can tell you that Alice[1] refers to the displayName.

type User = [id: number, displayName: string];

const Alice: User = [123, 'Alice']; // OK
console.log(Alice[1]); // (property) 1: string (displayName)
Enter fullscreen mode Exit fullscreen mode

try in playground

Why Use Tuples?

You might wonder why anyone would use an array to hold structured data like this; wouldn't an object be a more natural choice?

const Alice = { id: 123, displayName: 'Alice' };
Enter fullscreen mode Exit fullscreen mode

While objects with explicit keys and values are generally considered more readable, there are legitimate use cases for using structured arrays instead. For example, if user data were read from a database or file, working with whatever format it was returned in might be more efficient rather than converting it to an object.

Tuples are particularly useful for representing a small set of related, ordered values.

  • Coordinates: [latitude: number, longitude: number]
  • RGB color values: [red: number, green: number, blue: number]
  • API responses: [status: number, message: string]

Example Uses of Tuples in TypeScript:

Named Tuple Elements

type User = [id: number, displayName: string];

let user: User = [123, "Alice"]; // OK

console.log(user[0]); // (property) 0: number (id)
console.log(user[1]); // (property) 1: string (displayName)

user = ["Alice", 123]; // ERROR Type 'string' is not assignable to type 'number'.
user = [456, "Bob", true]; // ERROR Type '[number, string, boolean]' is not assignable to type 'User'. Source has 3 element(s) but target allows only 2
Enter fullscreen mode Exit fullscreen mode

try in playground

Optional Tuple Elements

You can make elements in a tuple optional by appending a ? to their type. Optional elements must come after any required elements.

type Person = [firstName: string, lastName: string, age?: number];

const person1: Person = ["John", "Doe"]; // OK
const person2: Person = ["Jane", "Doe", 42]; // OK

const person3: Person = ["Jack", 12]; // ERROR Type 'number' is not assignable to type 'string'.
Enter fullscreen mode Exit fullscreen mode

try in playground

Rest Elements in Tuple Types

Rest elements allow you to define a tuple with some fixed elements at the beginning, followed by an unknown number of elements of a specific type.

type LogEntry = [
  timestamp: number,
  level: 'INFO' | 'WARN' | 'ERROR',
  ...messages: string[], // NOTE Can be zero or more messages.
];

const entry1: LogEntry = [Date.now(), 'INFO', 'User logged in'];
const entry2: LogEntry = [
  Date.now(),
  'ERROR',
  'Failed to connect to database',
  'Network error',
  'Retry attempts: 3',
];
Enter fullscreen mode Exit fullscreen mode

try in playground

Readonly Tuples

You can make a tuple immutable using the readonly modifier. This prevents modification to the tuple's elements (e.g., push, pop, direct assignment to an index).

type Point = readonly [x: number, y: number];

let p: Point = [0, 0];

p[0] = 1; // ERROR Cannot assign to '0' because it is a read-only property.
p.push(5); // ERROR Property 'push' does not exist on type 'Point'.
Enter fullscreen mode Exit fullscreen mode

try in playground

Top comments (1)

Collapse
 
andyrosenberg profile image
AndyRosenberg

I've almost never seen a use case for Tuples in the wild that can't be solved by other data structures. That being said, I think you make a good case here for why someone would want to use one.