Skip to content

Generics

Suppose you want a function that returns whatever you give it. Without generics you face a bad choice:

// Option A: one type only — not reusable
function identityStr(x: string): string { return x; }
// Option B: any — reusable, but throws away all type information
function identityAny(x: any): any { return x; }
const a = identityAny(42);
a.toUpperCase(); // 💥 no error at compile time — any hides the bug

any makes the function reusable but blinds the compiler: the link between the input type and the output type is gone. Generics keep that link.

function identity<T>(x: T): T { return x; }
const n = identity(42); // T inferred as number → n: number
const s = identity("hi"); // T inferred as string → s: string
n.toUpperCase(); // ❌ Error: number has no toUpperCase — the bug is caught

T is a type parameter — a placeholder the caller (or inference) fills in. The function works for every type, and the return type still tracks the argument type exactly.

A generic is a function at the type level: it takes types as input and produces types as output. identity<T> says “for any type T, take a T and return a T.” This is called parametric polymorphism — one implementation, parameterized over types.

flowchart LR
  impl["one generic
identity of T"] --> callN["called with number
returns number"]
  impl --> callS["called with string
returns string"]
  impl --> callU["called with User
returns User"]
A generic is one implementation over many types
LessonWhat you’ll learn
Functions & constraintsType parameters, extends constraints, default type parameters
Classes & interfacesGeneric classes, interfaces, and per-method type parameters
Conditional typesT extends U ? X : Y and distribution over unions
Inference & inferHow type arguments are inferred, and extracting types with infer
What do generics preserve that `any` throws away?
In `function identity<T>(x: T): T`, what is `T`?
What is the name for "one implementation parameterized over types"?