TypeScript Generics Cheatsheet
typescriptTypeScript generics syntax and patterns reference.
Basic Generic Syntax
function fn<T>(arg: T): T { }Declares a function with a type parameter T that can be inferred or specified
function identity<T>(value: T): T { return value; }
identity<string>('hello');const fn = <T>(arg: T): T => argArrow function syntax for generics using angle brackets before parameters
const toArray = <T>(item: T): T[] => [item];interface Name<T> { prop: T; }Interface with a generic type parameter for flexible typing
interface Box<T> { value: T; }
const box: Box<number> = { value: 42 };type Name<T> = { prop: T }Type alias using generic parameters for reusable type definitions
type Response<T> = { data: T; status: number };class Name<T> { value: T; }Class with generic type parameter for type-safe instances
class Stack<T> { items: T[] = []; push(item: T) { this.items.push(item); } }class C { method<T>(arg: T): T { } }Method within a class that has its own generic type parameter
class Utils { wrap<T>(value: T): T[] { return [value]; } }Multiple Type Parameters
function fn<T, U>(a: T, b: U): [T, U]Function accepting multiple different generic types
function pair<T, U>(first: T, second: U): [T, U] { return [first, second]; }function fn<T, K extends keyof T>(obj: T, key: K)Second type parameter constrained by the first
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }interface Name<K, V> { key: K; value: V; }Interface with multiple generic parameters for key-value structures
interface KeyValue<K, V> { key: K; value: V; }<T, U, V>(a: T, b: U, c: V) => [T, U, V]Transform multiple inputs into typed tuple output
const tuple = <T, U, V>(a: T, b: U, c: V): [T, U, V] => [a, b, c];Constraints and Defaults
<T extends Type>Constrains generic to types that extend or implement Type
function len<T extends { length: number }>(arg: T): number { return arg.length; }<K extends keyof T>Constrains K to be a key of type T
function getKey<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }<T extends string | number>Constrains generic to specific union of types
function format<T extends string | number>(value: T): string { return String(value); }<T extends new (...args: any[]) => any>Constrains T to be a constructor function
function create<T extends new () => any>(ctor: T): InstanceType<T> { return new ctor(); }<T = DefaultType>Provides a default type when none is specified
interface Container<T = string> { value: T; }
const c: Container = { value: 'hi' };<T extends Base = Default>Combines constraint with default type parameter
type EventHandler<T extends Event = MouseEvent> = (e: T) => void;<T = string, U = number>Multiple type parameters each with their own defaults
interface Cache<K = string, V = any> { get(key: K): V; set(key: K, val: V): void; }Conditional Types
T extends U ? X : YReturns X if T extends U, otherwise Y
type IsString<T> = T extends string ? true : false;
type A = IsString<'hi'>; // trueT extends A ? X : T extends B ? Y : ZChain multiple conditional type checks
type TypeName<T> = T extends string ? 'string' : T extends number ? 'number' : 'other';type D<T> = T extends any ? T[] : neverDistributes over union types when T is naked type parameter
type ToArray<T> = T extends any ? T[] : never;
type R = ToArray<string | number>; // string[] | number[][T] extends [U] ? X : YWrap in tuple to prevent distribution over unions
type Boxed<T> = [T] extends [any] ? { box: T } : never;T extends Excluded ? never : TFilter out types from a union by returning never
type NoNull<T> = T extends null | undefined ? never : T;
type R = NoNull<string | null>; // stringExtract<T, U>Built-in type that extracts from T types assignable to U
type T = Extract<'a' | 'b' | 1, string>; // 'a' | 'b'Exclude<T, U>Built-in type that excludes from T types assignable to U
type T = Exclude<'a' | 'b' | 1, string>; // 1Infer Keyword
T extends Type<infer U> ? U : DefaultInfers a type from within a conditional type pattern
type Unpack<T> = T extends Array<infer U> ? U : T;
type R = Unpack<string[]>; // stringT extends (...args: any) => infer R ? R : neverExtract the return type of a function type
type Return<T> = T extends (...args: any) => infer R ? R : never;T extends (...args: infer P) => any ? P : neverExtract the parameter types as a tuple
type Params<T> = T extends (...args: infer P) => any ? P : never;T extends Promise<infer U> ? U : TUnwrap the resolved type from a Promise
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;T extends [infer First, ...any[]] ? First : neverExtract the first element type from a tuple
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;T extends [any, ...infer Rest] ? Rest : neverExtract all but the first element from a tuple
type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never;T extends { a: infer A; b: infer B } ? [A, B] : neverInfer multiple types from a single pattern match
type Props<T> = T extends { name: infer N; age: infer A } ? [N, A] : never;Mapped Types
{ [K in keyof T]: NewType }Transform each property of T to a new type
type Stringify<T> = { [K in keyof T]: string };{ [K in keyof T]?: T[K] }Make all properties optional in the mapped type
type MyPartial<T> = { [K in keyof T]?: T[K] };{ readonly [K in keyof T]: T[K] }Make all properties readonly in the mapped type
type MyReadonly<T> = { readonly [K in keyof T]: T[K] };{ [K in keyof T]-?: T[K] }Remove optional modifier from properties using minus
type Required<T> = { [K in keyof T]-?: T[K] };{ -readonly [K in keyof T]: T[K] }Remove readonly modifier from all properties
type Mutable<T> = { -readonly [K in keyof T]: T[K] };{ [K in keyof T as NewKey]: T[K] }Transform property keys using as clause
type Getters<T> = { [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K] };{ [K in keyof T as Condition]: T[K] }Filter properties by returning never from as clause
type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] };{ [K in Keys]: T[K] }Select a subset of properties by their keys
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };{ [K in Keys]: Type }Create object type with specified keys and value type
type MyRecord<K extends keyof any, V> = { [P in K]: V };Template Literal Types
type T = `prefix${string}suffix`String type with literal prefix and suffix
type EventName = `on${string}`;
const e: EventName = 'onClick';type T = `${A | B}-${C | D}`Produces all combinations of union members
type Size = 'sm' | 'lg';
type Color = 'red' | 'blue';
type Combo = `${Size}-${Color}`;Uppercase<StringType>Convert string literal type to uppercase
type Upper = Uppercase<'hello'>; // 'HELLO'Lowercase<StringType>Convert string literal type to lowercase
type Lower = Lowercase<'HELLO'>; // 'hello'Capitalize<StringType>Capitalize first character of string literal type
type Cap = Capitalize<'hello'>; // 'Hello'Uncapitalize<StringType>Lowercase first character of string literal type
type Uncap = Uncapitalize<'Hello'>; // 'hello'T extends `${infer A}-${infer B}` ? [A, B] : neverExtract parts from template literal using infer
type Split<T> = T extends `${infer A}-${infer B}` ? [A, B] : never;`on${Capitalize<E>}`Common pattern for generating event handler names
type Handler<E extends string> = `on${Capitalize<E>}`;
type H = Handler<'click'>; // 'onClick'Advanced Patterns
type T<A> = A extends X ? Y : T<Transform<A>>Type that references itself for nested structures
type DeepReadonly<T> = { readonly [K in keyof T]: DeepReadonly<T[K]> };type Json = string | number | boolean | null | Json[] | { [k: string]: Json }Recursive type representing any valid JSON value
type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };{ [K in keyof T]?: DeepPartial<T[K]> }Recursively make all nested properties optional
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> };interface Co<out T> { }Type parameter used only in output positions
interface Producer<out T> { get(): T; }interface Contra<in T> { }Type parameter used only in input positions
interface Consumer<in T> { accept(value: T): void; }interface Inv<in out T> { }Type parameter used in both input and output positions
interface State<in out T> { get(): T; set(value: T): void; }T extends (infer U)[] ? U : TExtract element type from array or return type as-is
type Flatten<T> = T extends (infer U)[] ? U : T;
type R = Flatten<number[]>; // number(T extends any ? (x: T) => void : never) extends (x: infer R) => void ? R : neverConvert union type to intersection using contravariance
type UnionToIntersection<T> = (T extends any ? (x: T) => void : never) extends (x: infer R) => void ? R : never;T[number]Convert tuple or array type to union of element types
type TupleToUnion<T extends any[]> = T[number];
type U = TupleToUnion<[1, 2, 3]>; // 1 | 2 | 3T extends `${infer C}${infer R}` ? C | StringToUnion<R> : neverConvert string literal to union of characters
type Chars<T extends string> = T extends `${infer C}${infer R}` ? C | Chars<R> : never;