Generic Classes

Parameterize a class by type so one implementation serves every element type safely.

Classes take type parameters just like functions do. The parameter is in scope across the whole class body — fields, methods, return types — so a single implementation stays precise for whatever type a caller supplies.

class Box<T> {
  constructor(private value: T) {}
  get(): T { return this.value; }
  map<U>(fn: (v: T) => U): Box<U> {
    return new Box(fn(this.value));
  }
}

Note map introduces its own parameter U and returns a differently-typed Box — method-level generics compose with the class-level one. You can also constrain the class parameter (class Repo<T extends { id: string }>) to require an id on every stored item.

This is exactly how typed collections, result wrappers, and repositories are written in real codebases.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A typed EventEmitter<EventMap> class is generic so each event name is tied to its specific payload type.
  • A Repository<T, ID> class is generic so the same CRUD implementation works for any entity type.
  • A typed cache class Cache<K, V> parameterises both the key and value types for complete type safety.

More examples

Generic class basics

A generic Box class holds a single value whose type is fixed at construction, preventing type mismatch on set().

Example · ts
class Box<T> {
  private value: T;

  constructor(initial: T) { this.value = initial; }

  get(): T { return this.value; }
  set(v: T): void { this.value = v; }
}

const numBox = new Box(42);
const strBox = new Box('hello');

numBox.set(100);    // OK
numBox.set('oops'); // Error: Argument of type 'string' is not assignable

Generic class with constraint

Constrains T to comparable types so the sort call is safe, and the class can be reused for both numbers and strings.

Example · ts
class SortedList<T extends number | string> {
  private items: T[] = [];

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

  first(): T | undefined { return this.items[0]; }
}

const list = new SortedList<number>();
list.add(5); list.add(2); list.add(8);
console.log(list.first()); // 2

Two type parameters

Uses two type parameters K and V so key and value types are independently typed and constrained.

Example · ts
class Dictionary<K extends string, V> {
  private store: Record<string, V> = {};

  set(key: K, value: V): void { this.store[key] = value; }
  get(key: K): V | undefined   { return this.store[key]; }
  has(key: K): boolean          { return key in this.store; }
}

const d = new Dictionary<string, number>();
d.set('age', 30);
console.log(d.get('age')); // 30

Discussion

  • Be the first to comment on this lesson.
Generic Classes — TypeScript | SoundsCode