TypeScriptGenerics Mastery

Mastering Generics in TypeScript

Generics provide a way to create reusable components that work with any type while maintaining type safety.

Generic Functions

function identity(arg: T): T {
  return arg;
}

// Type inference const str = identity("hello"); // string const num = identity(42); // number

// Explicit type const explicit = identity("hello");

Generic Constraints

interface Lengthwise {
  length: number;
}

function loggingIdentity(arg: T): T { console.log(arg.length); // OK, we know it has length return arg; }

loggingIdentity("hello"); // OK loggingIdentity([1, 2, 3]); // OK loggingIdentity(42); // Error: number doesn't have length

Generic Classes

class DataStore {
  private items: T[] = [];

add(item: T): void { this.items.push(item); }

get(index: number): T | undefined { return this.items[index]; }

getAll(): T[] { return [...this.items]; } }

const stringStore = new DataStore(); stringStore.add("hello");

const numberStore = new DataStore(); numberStore.add(42);

Multiple Type Parameters

function pair(key: K, value: V): [K, V] {
  return [key, value];
}

const p1 = pair("age", 30); // [string, number] const p2 = pair(1, "one"); // [number, string]

// With constraints function getProperty(obj: T, key: K): T[K] { return obj[key]; }

const person = { name: "John", age: 30 }; const name = getProperty(person, "name"); // string const age = getProperty(person, "age"); // number

Generic Defaults

interface APIResponse {
  data: T;
  status: number;
  message: string;
}

// Uses default type const response: APIResponse = { data: null, status: 200, message: "OK" };

// Specifies type const userResponse: APIResponse = { data: { id: 1, name: "John", email: "john@example.com" }, status: 200, message: "OK" };