TypeScript Utility Types Deep Dive Cheat Sheet
Covers Partial, Pick, Omit, Record, Extract, Exclude, function-derived utility types, and string manipulation types with examples.
Partial, Required, Readonly, Pick, Omit
Derive new object shapes from an existing interface.
interface User { id: number; name: string; email: string; age?: number; }type PartialUser = Partial<User>; // all props optionaltype RequiredUser = Required<User>; // all props required (age no longer optional)type ReadonlyUser = Readonly<User>; // all props readonlytype UserPreview = Pick<User, 'id' | 'name'>; // { id: number; name: string }type UserWithoutEmail = Omit<User, 'email'>; // all props except email
Record, Extract, Exclude, NonNullable
Build and filter types based on unions and keys.
type Role = 'admin' | 'editor' | 'viewer';type Permissions = Record<Role, string[]>; // { admin: string[]; editor: string[]; viewer: string[] }type T1 = Extract<'a' | 'b' | 'c', 'a' | 'c'>; // 'a' | 'c'type T2 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'type T3 = NonNullable<string | null | undefined>; // string
ReturnType, Parameters, Awaited
Extract type information directly from function signatures.
function createUser(name: string, age: number) { return { name, age, id: crypto.randomUUID() };}type CreateUserReturn = ReturnType<typeof createUser>; // { name: string; age: number; id: string }type CreateUserParams = Parameters<typeof createUser>; // [name: string, age: number]async function fetchUser(): Promise<User> { /* ... */ return {} as User; }type FetchedUser = Awaited<ReturnType<typeof fetchUser>>; // User (unwraps the Promise)
String Manipulation Utility Types
Transform string literal types at compile time.
type Greeting = 'hello world';type T4 = Uppercase<Greeting>; // 'HELLO WORLD'type T5 = Lowercase<'FOO'>; // 'foo'type T6 = Capitalize<'foo'>; // 'Foo'type T7 = Uncapitalize<'Foo'>; // 'foo'// Often combined with template literal typestype EventName<T extends string> = `on${Capitalize<T>}`;type Click = EventName<'click'>; // 'onClick'
Quick Reference
The most commonly used built-in utility types.
- Partial<T>- Makes every property optional
- Required<T>- Makes every property required, removing optional modifiers
- Readonly<T>- Makes every property readonly
- Pick<T, K>- Builds a type with only the listed keys K
- Omit<T, K>- Builds a type with every key except K
- Record<K, V>- Builds an object type mapping each key in K to type V
- Exclude<T, U> / Extract<T, U>- Removes/keeps union members assignable to U
- ReturnType<T> / Parameters<T>- Extracts a function's return type or tuple of parameter types
- Awaited<T>- Recursively unwraps Promise types
- InstanceType<T>- Extracts the instance type of a class constructor type
Conditional Types & infer
Extract nested type information with conditional types and the infer keyword.
type UnwrapArray<T> = T extends (infer U)[] ? U : T;type Elem = UnwrapArray<string[]>; // stringtype UnwrapPromise<T> = T extends Promise<infer U> ? U : T;type Value = UnwrapPromise<Promise<number>>; // number// Distributive conditional types: applied member-by-member over a uniontype ToArray<T> = T extends any ? T[] : never;type Result = ToArray<string | number>; // string[] | number[]// Wrap in a tuple to opt OUT of distributiontype ToArrayNonDist<T> = [T] extends [any] ? T[] : never;type Result2 = ToArrayNonDist<string | number>; // (string | number)[]
Mapped Types with Key Remapping (as clause)
Rename, filter, or transform keys while building a mapped type.
interface Model { id: number; name: string; internal: boolean; }// Prefix every key with 'get' and turn it into a methodtype Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };type ModelGetters = Getters<Model>;// { getId: () => number; getName: () => string; getInternal: () => boolean }// Filter out keys whose value type is boolean using a 'never' remaptype OmitBooleans<T> = { [K in keyof T as T[K] extends boolean ? never : K]: T[K] };type WithoutFlags = OmitBooleans<Model>; // { id: number; name: string }
Hand-Rolled Recursive Deep Utilities
Built-ins only go one level deep - implement recursive variants for nested objects.
type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;type DeepReadonly<T> = T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]> } : T;interface Config { server: { host: string; port: number }; retries: number; }type PartialConfig = DeepPartial<Config>;// { server?: { host?: string; port?: number }; retries?: number }const frozen: DeepReadonly<Config> = { server: { host: 'a', port: 1 }, retries: 3 };// frozen.server.port = 2; // Error: read only property
satisfies Operator & Branded Types
Validate a literal against a type without widening it, and simulate nominal typing.
// satisfies checks shape but preserves the narrowed literal typeconst palette = { red: [255, 0, 0], green: '#00ff00',} satisfies Record<string, string | number[]>;palette.red[0]; // still typed as number, not string | number[]// Branded (nominal-ish) types prevent mixing structurally identical primitivestype UserId = string & { readonly __brand: 'UserId' };type OrderId = string & { readonly __brand: 'OrderId' };function asUserId(id: string): UserId { return id as UserId; }declare function getOrder(id: OrderId): void;// getOrder(asUserId('u1')); // Error: UserId is not assignable to OrderId
ThisParameterType & OmitThisParameter
Inspect or strip an explicit this parameter from a function type.
function toHex(this: { value: number }) { return this.value.toString(16);}type ThisArg = ThisParameterType<typeof toHex>; // { value: number }type PlainFn = OmitThisParameter<typeof toHex>; // () => stringconst bound: PlainFn = toHex.bind({ value: 255 });bound(); // 'ff' - callable without supplying `this` again
Advanced Type-Level Toolkit
Lesser-known constructs for building your own utility types.
- infer- Introduces a type variable inside a conditional type's extends clause to capture a matched subtype
- Distributive conditional types- A naked type parameter in a conditional type distributes over each member of a union
- as clause (key remapping)- Rewrites or filters keys in a mapped type; mapping a key to never removes it
- Template literal types- Compose string literal unions at the type level, e.g. `${'get'|'set'}${Capitalize<K>}`
- const type parameters- `<const T>` infers the narrowest literal type for an argument without needing `as const` at the call site
- ThisType<T>- Marker type used with object literals to contextually type `this` inside their methods
- Recursive conditional types- A conditional type may reference itself to walk arbitrarily nested structures (with a recursion depth limit)
Chain utility types instead of hand-writing derived shapes - e.g. Partial<Pick<User, 'name' | 'email'>> for a PATCH request body - so the derived type automatically stays in sync when the source interface changes.