TypeScript tuples provide a powerful way to work with arrays of fixed length and specific types. Unlike regular arrays, tuples let you define exactly what types can go in each position, making your code more predictable and type-safe. Let’s explore how to use them effectively.
Tuples are particularly useful when you need to work with arrays where you know exactly how many elements there will be and what type each element should be. Think of them as strict arrays with a predefined structure.
Table of Contents
- Basic Tuple Syntax
- Optional Elements in Tuples
- Named Tuple Elements
- Tuple Type Inference
- Rest Elements in Tuples
- Readonly Tuples
- Practical Use Cases
- Best Practices
- Common Pitfalls
- Integration with TypeScript Features
Basic Tuple Syntax
To declare a tuple in TypeScript, you specify the types in order within square brackets:
let coordinates: [number, number] = [10, 20];
Code language: JavaScript (javascript)
This creates a tuple that must contain exactly two numbers. Trying to assign different types or a different number of elements will result in a type error:
// Error: Type 'string' is not assignable to type 'number'
let invalidCoordinates: [number, number] = [10, "20"];
// Error: Source has 3 elements but target allows only 2
let tooManyCoordinates: [number, number] = [10, 20, 30];
Code language: JavaScript (javascript)
Optional Elements in Tuples
TypeScript 4.0 introduced optional elements in tuples. You can make tuple elements optional by adding a question mark:
type OptionalTuple = [string, number, boolean?];
let valid1: OptionalTuple = ["hello", 42, true];
let valid2: OptionalTuple = ["hello", 42];
Code language: JavaScript (javascript)
Named Tuple Elements
For better code readability, you can give names to tuple elements:
type Point = [x: number, y: number];
let point: Point = [10, 20];
console.log(`X: ${point[0]}, Y: ${point[1]}`);
Code language: JavaScript (javascript)
Tuple Type Inference
TypeScript can infer tuple types when you use const assertions:
let tuple = [10, "hello"] as const;
// Type is readonly [10, "hello"]
Code language: JavaScript (javascript)
Rest Elements in Tuples
You can use rest elements to allow additional elements of a specific type:
type StringNumberBooleans = [string, number, ...boolean[]];
let valid: StringNumberBooleans = ["hello", 42, true, false, true];
Code language: JavaScript (javascript)
Readonly Tuples
Make tuples immutable by using the readonly modifier:
type ReadOnlyPoint = readonly [number, number];
let point: ReadOnlyPoint = [10, 20];
// Error: Cannot assign to '0' because it is a read-only property
point[0] = 30;
Code language: JavaScript (javascript)
Practical Use Cases
Return Values from Functions
Tuples are excellent for functions that return multiple values:
function getUserInfo(): [string, number, boolean] {
return ["John Doe", 30, true];
}
const [name, age, isAdmin] = getUserInfo();
console.log(`${name} is ${age} years old`);
State Management
Tuples are commonly used in React with the useState hook:
type CounterState = [number, (value: number) => void];
function useCounter(): CounterState {
const [count, setCount] = useState(0);
return [count, setCount];
}
Code language: JavaScript (javascript)
Coordinate Systems
Tuples are perfect for representing coordinates or dimensions:
type Point2D = [x: number, y: number];
type Point3D = [x: number, y: number, z: number];
function calculateDistance(p1: Point2D, p2: Point2D): number {
const [x1, y1] = p1;
const [x2, y2] = p2;
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
Code language: JavaScript (javascript)
Best Practices
- Use tuples when you have a fixed number of elements with specific types.
- Consider using interfaces or types for more complex data structures.
- Name tuple elements when the meaning isn’t immediately clear from context.
- Use readonly tuples when the values shouldn’t change.
- Prefer named properties (interfaces) over tuples for public APIs.
Common Pitfalls
Mixing Up Element Order
// Bad: Order matters in tuples
type UserInfo = [number, string]; // [id, name]
let user: UserInfo = ["John", 1]; // Type error!
// Good: Use an interface when order shouldn't matter
interface User {
id: number;
name: string;
}
Code language: PHP (php)
Forgetting Type Annotations
// Bad: Type inference won't create a tuple
let point = [10, 20];
point.push(30); // Allowed because it's inferred as number[]
// Good: Explicitly type as tuple
let coordinates: [number, number] = [10, 20];
// point.push(30); // Error!
Code language: JavaScript (javascript)
Integration with TypeScript Features
Tuples work seamlessly with other TypeScript features like mapped types and conditional types:
type ToObject<T extends readonly any[]> = {
[K in keyof T]: T[K];
};
type PointTuple = [x: number, y: number];
type PointObject = ToObject<PointTuple>; // { 0: number, 1: number }
Code language: HTML, XML (xml)
Tuples are an essential part of TypeScript’s type system, providing a way to work with fixed-length arrays where the type of each element matters. They’re particularly useful in functional programming patterns and when working with APIs that return multiple values.
By understanding and properly using tuples, you can write more type-safe and maintainable TypeScript code. Remember to consider whether a tuple is the right choice for your use case – sometimes interfaces or regular arrays might be more appropriate.
Explore more TypeScript features in our other guides, such as our TypeScript Generics guide for advanced type manipulation techniques.