Tuples

1. Welcome and Icebreaker:

  • Hi there! If you were a data type, which one would you be and why? (e.g., a flexible array, a strict number, a boolean with only two states!)

2. Outline the Session:

  • Today’s topic is Tuples in TypeScript.
  • We will learn: what tuples are, how to declare them, their use cases, and how they differ from arrays.
  • Learning Outcomes: You’ll understand when and how to use tuples for fixed-length arrays with specific types.
  • Questions are welcome anytime!

3. Concept Explanation:

  • Tuples are a special type of array in TypeScript with a fixed number of elements whose types are known and pre-defined. The order of types matters.
  • Unlike regular arrays where the type applies to all elements (e.g., number[] means an array of numbers), a tuple defines the type for each specific index.
  • Declaring Tuples: let person: [string, number]; This declares a tuple named person that must have exactly two elements: the first must be a string, and the second must be a number.
  • Use Cases:
    • Representing data where the order and type of each element are important, like a key-value pair, coordinates (x, y), or RGB color values.
    • Returning multiple, differently-typed values from a function without using an object.
  • Difference from Arrays:
    • Fixed Length: Tuples have a defined length. Trying to access an element outside its defined range or assign an array of a different length will result in an error.
    • Fixed Types per Index: Each element in a tuple has a specific type associated with its position.

4. Live Coding Demonstration:

// Declaring a tuple
let userProfile: [string, number, boolean];

// Initializing the tuple
userProfile = ["Alice", 30, true];
// userProfile = [30, "Alice", true]; // Error: Type 'number' is not assignable to type 'string'.
// userProfile = ["Bob", 25]; // Error: Type '[string, number]' is not assignable to type '[string, number, boolean]'. Source has 2 element(s) but target requires 3.

console.log("User Profile:", userProfile);

// Accessing tuple elements
console.log("Username:", userProfile[0]); // Alice
console.log("Age:", userProfile[1]); // 30
console.log("Is Active:", userProfile[2]); // true

// Modifying tuple elements (must match the type at that index)
userProfile[0] = "Bob";
// userProfile[1] = "twenty-five"; // Error: Type 'string' is not assignable to type 'number'.
userProfile[1] = 25;

console.log("Updated User Profile:", userProfile);

// Tuple with optional elements (TypeScript 3.0+)
// Optional tuple elements can only appear at the end.
let httpStatusCode: [number, string, string?];
httpStatusCode = [200, "OK"];
console.log("HTTP Status (OK):", httpStatusCode);
httpStatusCode = [404, "Not Found", "The requested resource was not found on this server."];
console.log("HTTP Status (Not Found with details):", httpStatusCode);

// Destructuring tuples
let [username, age, isActive] = userProfile;
console.log(`Destructured: Name=${username}, Age=${age}, Active=${isActive}`);

// Tuples in function return types
function getCoordinates(): [number, number] {
  return [10.5, 25.3];
}

let coordinates: [number, number] = getCoordinates();
console.log("Coordinates:", coordinates);
let [x, y] = getCoordinates();
console.log(`X: ${x}, Y: ${y}`);

// Attempting to access out-of-bounds element (compile-time error for known indices)
// console.log(userProfile[3]); // Error: Tuple type '[string, number, boolean]' of length '3' has no element at '3'.

// However, array methods like push can still add elements, 
// but TypeScript will only allow types that are part of the tuple's defined types (union of types).
// This is a known quirk and generally, tuples are best used for their fixed-length nature.
// userProfile.push("test"); // Allowed if 'test' is string, number or boolean
// console.log("User profile after push:", userProfile);
// It's best to treat tuples as fixed-length and fixed-type structures.

5. Tasks:

  • Short Exercise:
    1. Define a tuple type Book that represents a book with the following properties in order: title (string), author (string), and yearPublished (number).
    2. Create a variable of type Book and initialize it with data for your favorite book.
    3. Print the author of the book from your tuple.
    4. Try to assign a new value to the yearPublished with a string. Observe the TypeScript error.
    5. Create a function getBookDetails that takes a Book tuple as an argument and returns a string formatted as: “[Title] by [Author], published in [Year]”. Call this function with your book tuple and print the result.