The generics patterns you reach for, grouped by job: declare a type parameter, constrain it, default it, branch with a conditional, capture with infer, and map over a shape. Each row pairs the pattern with a one-line example.
A generic is a type parameter: a placeholder for a type the caller chooses, so one function or type works for many shapes without losing precision. Read <T> as for some type T. The power comes from constraining T, branching on it, and mapping over it. The patterns below are the working vocabulary.
Reference table · 28 entries
TypeScript GenericsExplained
28 of 28 rows
Declare
A type parameter the caller picks.
function first<T>(xs: T[]): T
Several independent type parameters.
function pair<T, U>(a: T, b: U): [T, U]
A second parameter tied to the keys of the first.
function get<T, K extends keyof T>(o: T, k: K): T[K]
A class with a type parameter on its fields and methods.
class Box<T> { value: T }
An object shape with a type parameter.
interface Result<T> { data: T }
A type parameter on an arrow function; the trailing comma stops .tsx files from reading it as JSX.
const first = <T,>(xs: T[]): T => xs[0]
Constrain
Require T to be assignable to Type.
function len<T extends { length: number }>(x: T)
Constrain T to a key of another type.
type Keys<O> = keyof O
Constrain T to a constructable class.
function make<C extends new () => C>(c: C): C
Require T to satisfy several constraints at once.
function log<T extends Error & { code: number }>(e: T)
Constrain to anything; keeps the parameter generic without narrowing it.
type Wrap<T> = T extends unknown ? { v: T } : never
Default & infer
Give T a default when the caller omits it.
function parse<T = string>(): T
Capture a type inside a conditional.
type El<T> = T extends Array<infer I> ? I : never
Unwrap a nested Promise to its inner type.
type Data = Awaited<Promise<User>>
Capture one piece of a template literal type.
type Path<S> = S extends `/api/${infer R}` ? R : never
Check the whole union at once; a naked T infers one member at a time.
type El<T> = [T] extends [Array<infer I>] ? I : never
Conditional & mapped
Pick a type based on whether T is assignable to U.
type IsStr<T> = T extends string ? true : false
Build a new object type by transforming each key of T.
type Frozen<T> = { [K in keyof T]: Readonly<T[K]> }
An object whose keys are K and values are V.
type Scores = Record<string, number>
Built-in generics derived from the patterns above.
type Preview = Pick<User, "id" | "name">
A bare T before extends runs once per union member and unions the results.
ToArray<'a' | 'b'> = 'a'[] | 'b'[]
Add or remove modifiers on mapped keys.
type Req<T> = { [K in keyof T]-?: T[K] }
The keys of a runtime value, as a type.
const opts = { a: 1 }; type K = keyof typeof opts
Build a string type from other string types.
type Route = `/users/${string}`
Join tuple types end to end.
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U]
A type whose definition refers to itself.
type Json = string | number | Json[] | { [k: string]: Json }
Check a value against a type and keep its narrower literal type.
const c = { dark: "#000" } satisfies Record<string, string>
Keep the caller's literal type instead of widening it (TS 5.0).