Skip to content

Understanding Generics in Typescript

Generics in TypeScript allow you to create reusable and flexible components, such as functions, classes, or interfaces.

Generics allows you to work with a variety of data types while still preserving type safety.

Common Use Cases

Basic Syntax

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

const num = identity<number>(42);  // T is number
const str = identity("hello");     // T is inferred as string

Generic Functions

function logAndReturn<T>(value: T): T {
    console.log(value);
    return value;
}

const str = logAndReturn("test");  // type of result is string
const num = logAndReturn(5);       // type of result is number

Generic Interfaces

interface Box<T> {
  value: T;
}

const stringBox: Box<string> = { value: "hello" };
const numberBox: Box<number> = { value: 123 };

Generic Classes

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

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

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

const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);

console.log(numberStack.pop()); // 3
console.log(numberStack.pop()); // 2
console.log(numberStack.pop()); // 1

Generic Constraints

You can constrain generics to certain types using the extends keyword:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

loggingIdentity("hello");  // OK - string has .length
loggingIdentity([1, 2, 3]); // OK - array has .length
loggingIdentity(42);      // Error - number doesn't have .length

Summary