~/hackweb.dev
TypeScript Generics
Quiz
...

TypeScript Generics

beginner · updated Tue Sep 08 2026Contribute

Master generic functions, classes, and constraints.

TypeScript Generics

Generics let you write reusable code that works with any type while maintaining type safety.

What Are Generics?

Generics are type placeholders specified when the code is used:

function identity<T>(value: T): T {
  return value;
}

let num = identity<number>(42);      // number
let str = identity<string>("hello"); // string

Why generics? They let you write functions that work with multiple types without losing type safety.

Generic Functions

Type parameters are inferred from arguments automatically:

function first<T>(arr: T[]): T | undefined {
  return arr[0];
}

function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second];
}

let combo = pair("hello", 42); // [string, number]

Generic Interfaces and Classes

Interfaces and classes can also be generic:

interface Container<T> {
  value: T;
  getValue(): T;
}

class Stack<T> {
  private items: T[] = [];

  push(item: T): void { this.items.push(item); }
  pop(): T | undefined { return this.items.pop(); }
}

let numberStack = new Stack<number>();
numberStack.push(1);

Generic Constraints

Use extends to restrict what types can be used:

interface Lengthwise {
  length: number;
}

function logLength<T extends Lengthwise>(item: T): void {
  console.log(item.length);
}

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

Tip: Constraints ensure generic code only works with types that have the required properties.

Default Type Parameters

TypeScript allows default types when none is specified:

interface Response<T = string> {
  data: T;
  status: number;
}

let textResponse: Response = { data: "hello", status: 200 };
let numResponse: Response<number> = { data: 42, status: 200 };

Key Utility Pattern

Use keyof for type-safe property access:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

let name = getProperty({ name: "John", age: 25 }, "name");

Best Practices

  • Use generic constraints to ensure types have required properties
  • Let TypeScript infer types when possible
  • Use default type parameters for common combinations
  • Keep generics simple — don’t over-complicate type parameters
  • Use keyof for type-safe property access

Common Mistakes

  • Using generics without constraints when the type needs specific properties
  • Specifying too many type parameters makes code harder to read
  • Always specifying type parameters explicitly instead of inferring
  • Using any inside generics defeats their purpose