Generics

Intro to Generics
Generics are one of TypeScript's most powerful featuresβ€”and a cornerstone of functional programming. They let you write reusable transformations that work with multiple types while maintaining type safety.
// Without generics - only works with numbers
function firstNumber(arr: Array<number>): number | undefined {
	return arr[0]
}

// With generics - works with ANY type
function first<Item>(arr: Array<Item>): Item | undefined {
	return arr[0]
}

first([1, 2, 3]) // Item is number, returns number | undefined
first(['a', 'b']) // Item is string, returns string | undefined

The Problem Generics Solve

Without generics, you'd need to either:
  1. Write duplicate code for each type
  2. Use any and lose type safety
// Bad: Duplicated code
function firstString(arr: Array<string>): string | undefined { ... }
function firstNumber(arr: Array<number>): number | undefined { ... }
function firstUser(arr: Array<User>): User | undefined { ... }

// Bad: Loses type safety
function first(arr: Array<any>): any { ... }

// Good: Generic - type-safe and reusable
function first<Item>(arr: Array<Item>): Item | undefined { ... }

Generics Are Everywhere

You've already been using generics! Array<Item>, Promise<ResponseText>, and many more:
const numbers: Array<number> = [1, 2, 3]
const promise: Promise<ResponseText> = fetch('/api').then((r) => r.text())
Think of generics as type-level functionsβ€”just like functions transform values, generic types transform types. Array<Item> is a function that takes a type Item and returns the type "array of Item". This is the foundation of functional type-level programming.
In this exercise, you'll learn to write and use generic code.