{ ILoveJS }

TypeScript Generics Cheatsheet

typescript

TypeScript generics syntax and patterns reference.

8 sections · 58 items

Basic Generic Syntax

Generic Function
function fn<T>(arg: T): T { }

Declares a function with a type parameter T that can be inferred or specified

typescript
function identity<T>(value: T): T { return value; }
identity<string>('hello');
Generic Arrow Function
const fn = <T>(arg: T): T => arg

Arrow function syntax for generics using angle brackets before parameters

typescript
const toArray = <T>(item: T): T[] => [item];
Generic Interface
interface Name<T> { prop: T; }

Interface with a generic type parameter for flexible typing

typescript
interface Box<T> { value: T; }
const box: Box<number> = { value: 42 };
Generic Type Alias
type Name<T> = { prop: T }

Type alias using generic parameters for reusable type definitions

typescript
type Response<T> = { data: T; status: number };
Generic Class
class Name<T> { value: T; }

Class with generic type parameter for type-safe instances

typescript
class Stack<T> { items: T[] = []; push(item: T) { this.items.push(item); } }
Generic Method
class C { method<T>(arg: T): T { } }

Method within a class that has its own generic type parameter

typescript
class Utils { wrap<T>(value: T): T[] { return [value]; } }

Multiple Type Parameters

Two Type Parameters
function fn<T, U>(a: T, b: U): [T, U]

Function accepting multiple different generic types

typescript
function pair<T, U>(first: T, second: U): [T, U] { return [first, second]; }
Related Type Parameters
function fn<T, K extends keyof T>(obj: T, key: K)

Second type parameter constrained by the first

typescript
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }
Multiple Params in Interface
interface Name<K, V> { key: K; value: V; }

Interface with multiple generic parameters for key-value structures

typescript
interface KeyValue<K, V> { key: K; value: V; }
Tuple Transformation
<T, U, V>(a: T, b: U, c: V) => [T, U, V]

Transform multiple inputs into typed tuple output

typescript
const tuple = <T, U, V>(a: T, b: U, c: V): [T, U, V] => [a, b, c];

Constraints and Defaults

Extends Constraint
<T extends Type>

Constrains generic to types that extend or implement Type

typescript
function len<T extends { length: number }>(arg: T): number { return arg.length; }
Keyof Constraint
<K extends keyof T>

Constrains K to be a key of type T

typescript
function getKey<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }
Union Constraint
<T extends string | number>

Constrains generic to specific union of types

typescript
function format<T extends string | number>(value: T): string { return String(value); }
Constructor Constraint
<T extends new (...args: any[]) => any>

Constrains T to be a constructor function

typescript
function create<T extends new () => any>(ctor: T): InstanceType<T> { return new ctor(); }
Default Type Parameter
<T = DefaultType>

Provides a default type when none is specified

typescript
interface Container<T = string> { value: T; }
const c: Container = { value: 'hi' };
Constrained Default
<T extends Base = Default>

Combines constraint with default type parameter

typescript
type EventHandler<T extends Event = MouseEvent> = (e: T) => void;
Multiple Defaults
<T = string, U = number>

Multiple type parameters each with their own defaults

typescript
interface Cache<K = string, V = any> { get(key: K): V; set(key: K, val: V): void; }

Conditional Types

Basic Conditional
T extends U ? X : Y

Returns X if T extends U, otherwise Y

typescript
type IsString<T> = T extends string ? true : false;
type A = IsString<'hi'>; // true
Nested Conditional
T extends A ? X : T extends B ? Y : Z

Chain multiple conditional type checks

typescript
type TypeName<T> = T extends string ? 'string' : T extends number ? 'number' : 'other';
Distributive Conditional
type D<T> = T extends any ? T[] : never

Distributes over union types when T is naked type parameter

typescript
type ToArray<T> = T extends any ? T[] : never;
type R = ToArray<string | number>; // string[] | number[]
Non-Distributive
[T] extends [U] ? X : Y

Wrap in tuple to prevent distribution over unions

typescript
type Boxed<T> = [T] extends [any] ? { box: T } : never;
Never Filtering
T extends Excluded ? never : T

Filter out types from a union by returning never

typescript
type NoNull<T> = T extends null | undefined ? never : T;
type R = NoNull<string | null>; // string
Extract Utility
Extract<T, U>

Built-in type that extracts from T types assignable to U

typescript
type T = Extract<'a' | 'b' | 1, string>; // 'a' | 'b'
Exclude Utility
Exclude<T, U>

Built-in type that excludes from T types assignable to U

typescript
type T = Exclude<'a' | 'b' | 1, string>; // 1

Infer Keyword

Basic Infer
T extends Type<infer U> ? U : Default

Infers a type from within a conditional type pattern

typescript
type Unpack<T> = T extends Array<infer U> ? U : T;
type R = Unpack<string[]>; // string
Infer Function Return
T extends (...args: any) => infer R ? R : never

Extract the return type of a function type

typescript
type Return<T> = T extends (...args: any) => infer R ? R : never;
Infer Function Parameters
T extends (...args: infer P) => any ? P : never

Extract the parameter types as a tuple

typescript
type Params<T> = T extends (...args: infer P) => any ? P : never;
Infer Promise Value
T extends Promise<infer U> ? U : T

Unwrap the resolved type from a Promise

typescript
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
Infer First Element
T extends [infer First, ...any[]] ? First : never

Extract the first element type from a tuple

typescript
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;
Infer Rest Elements
T extends [any, ...infer Rest] ? Rest : never

Extract all but the first element from a tuple

typescript
type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never;
Multiple Infers
T extends { a: infer A; b: infer B } ? [A, B] : never

Infer multiple types from a single pattern match

typescript
type Props<T> = T extends { name: infer N; age: infer A } ? [N, A] : never;

Mapped Types

Basic Mapped Type
{ [K in keyof T]: NewType }

Transform each property of T to a new type

typescript
type Stringify<T> = { [K in keyof T]: string };
Optional Modifier
{ [K in keyof T]?: T[K] }

Make all properties optional in the mapped type

typescript
type MyPartial<T> = { [K in keyof T]?: T[K] };
Readonly Modifier
{ readonly [K in keyof T]: T[K] }

Make all properties readonly in the mapped type

typescript
type MyReadonly<T> = { readonly [K in keyof T]: T[K] };
Remove Modifier
{ [K in keyof T]-?: T[K] }

Remove optional modifier from properties using minus

typescript
type Required<T> = { [K in keyof T]-?: T[K] };
Remove Readonly
{ -readonly [K in keyof T]: T[K] }

Remove readonly modifier from all properties

typescript
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
Key Remapping
{ [K in keyof T as NewKey]: T[K] }

Transform property keys using as clause

typescript
type Getters<T> = { [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K] };
Filter Keys
{ [K in keyof T as Condition]: T[K] }

Filter properties by returning never from as clause

typescript
type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] };
Pick Implementation
{ [K in Keys]: T[K] }

Select a subset of properties by their keys

typescript
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };
Record Implementation
{ [K in Keys]: Type }

Create object type with specified keys and value type

typescript
type MyRecord<K extends keyof any, V> = { [P in K]: V };

Template Literal Types

Basic Template
type T = `prefix${string}suffix`

String type with literal prefix and suffix

typescript
type EventName = `on${string}`;
const e: EventName = 'onClick';
Union in Template
type T = `${A | B}-${C | D}`

Produces all combinations of union members

typescript
type Size = 'sm' | 'lg';
type Color = 'red' | 'blue';
type Combo = `${Size}-${Color}`;
Uppercase Intrinsic
Uppercase<StringType>

Convert string literal type to uppercase

typescript
type Upper = Uppercase<'hello'>; // 'HELLO'
Lowercase Intrinsic
Lowercase<StringType>

Convert string literal type to lowercase

typescript
type Lower = Lowercase<'HELLO'>; // 'hello'
Capitalize Intrinsic
Capitalize<StringType>

Capitalize first character of string literal type

typescript
type Cap = Capitalize<'hello'>; // 'Hello'
Uncapitalize Intrinsic
Uncapitalize<StringType>

Lowercase first character of string literal type

typescript
type Uncap = Uncapitalize<'Hello'>; // 'hello'
Infer in Template
T extends `${infer A}-${infer B}` ? [A, B] : never

Extract parts from template literal using infer

typescript
type Split<T> = T extends `${infer A}-${infer B}` ? [A, B] : never;
Event Handler Pattern
`on${Capitalize<E>}`

Common pattern for generating event handler names

typescript
type Handler<E extends string> = `on${Capitalize<E>}`;
type H = Handler<'click'>; // 'onClick'

Advanced Patterns

Recursive Type
type T<A> = A extends X ? Y : T<Transform<A>>

Type that references itself for nested structures

typescript
type DeepReadonly<T> = { readonly [K in keyof T]: DeepReadonly<T[K]> };
JSON Type
type Json = string | number | boolean | null | Json[] | { [k: string]: Json }

Recursive type representing any valid JSON value

typescript
type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };
Deep Partial
{ [K in keyof T]?: DeepPartial<T[K]> }

Recursively make all nested properties optional

typescript
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> };
Covariance
interface Co<out T> { }

Type parameter used only in output positions

typescript
interface Producer<out T> { get(): T; }
Contravariance
interface Contra<in T> { }

Type parameter used only in input positions

typescript
interface Consumer<in T> { accept(value: T): void; }
Invariance
interface Inv<in out T> { }

Type parameter used in both input and output positions

typescript
interface State<in out T> { get(): T; set(value: T): void; }
Flatten Array
T extends (infer U)[] ? U : T

Extract element type from array or return type as-is

typescript
type Flatten<T> = T extends (infer U)[] ? U : T;
type R = Flatten<number[]>; // number
Union to Intersection
(T extends any ? (x: T) => void : never) extends (x: infer R) => void ? R : never

Convert union type to intersection using contravariance

typescript
type UnionToIntersection<T> = (T extends any ? (x: T) => void : never) extends (x: infer R) => void ? R : never;
Tuple to Union
T[number]

Convert tuple or array type to union of element types

typescript
type TupleToUnion<T extends any[]> = T[number];
type U = TupleToUnion<[1, 2, 3]>; // 1 | 2 | 3
String to Union
T extends `${infer C}${infer R}` ? C | StringToUnion<R> : never

Convert string literal to union of characters

typescript
type Chars<T extends string> = T extends `${infer C}${infer R}` ? C | Chars<R> : never;

Related Content