TypeScript Utility Types Cheatsheet
A practical reference for TypeScript utility types: Partial, Pick, Omit, Record, Readonly, ReturnType, and a dozen more with real examples.
What you'll learn
- ✓The most-used utility types with examples
- ✓When to reach for each one
- ✓How they compose into custom helpers
- ✓Patterns for transforming object types
- ✓Pitfalls when combining them
Prerequisites
- •Comfortable with basic TypeScript
TypeScript ships with a small but powerful set of generic utility types that transform other types. Once you know them, you stop writing repetitive interfaces and start expressing intent: “the same as User but everything is optional,” “a map from action names to handlers,” “the return type of this function.” This cheatsheet walks through the ones you will use weekly.
What and why
A utility type is a generic that takes one type and returns a derived type. They live in lib.es5.d.ts and friends, always in PascalCase. They are not runtime constructs; they exist only in the type system. The benefit is keeping a single source of truth: change User and every type derived from it updates automatically.
Mental model
Think of each utility as a pure function in the type universe. It takes types in, returns a new type out. They compose like any other function.
User -> Partial<User> all optional
User -> Required<User> all required
User -> Readonly<User> no mutation
User -> Pick<User, 'id'> subset of keys
User -> Omit<User, 'id'> complement of keys
'a'|'b' -> Record<K, V> object map
fn -> ReturnType<fn> result of a function
fn -> Parameters<fn> args as tuple Hands-on examples
Given:
interface User {
id: string;
name: string;
email: string;
age?: number;
}
Partial<T> makes every property optional. Useful for patch payloads.
function updateUser(id: string, patch: Partial<User>) { /* ... */ }
updateUser('1', { name: 'Yash' }); // ok
Required<T> is the inverse; every property becomes required.
type FullUser = Required<User>; // age is now required
Readonly<T> freezes the shape.
const u: Readonly<User> = { id: '1', name: 'a', email: 'b' };
// u.name = 'c'; // error
Pick<T, K> selects a subset of keys.
type UserSummary = Pick<User, 'id' | 'name'>;
Omit<T, K> removes keys.
type UserPublic = Omit<User, 'email'>;
Record<K, V> builds an object type with the given keys and value type.
type Roles = Record<'admin' | 'editor' | 'viewer', string[]>;
ReturnType<typeof fn> and Parameters<typeof fn> extract the shape of a function.
function createUser(name: string, age: number) {
return { id: crypto.randomUUID(), name, age };
}
type CreatedUser = ReturnType<typeof createUser>;
type CreateArgs = Parameters<typeof createUser>; // [string, number]
Awaited<T> unwraps a promise (recursively).
type R = Awaited<Promise<Promise<number>>>; // number
NonNullable<T> strips null and undefined.
type S = NonNullable<string | null | undefined>; // string
Extract<T, U> and Exclude<T, U> filter unions.
type Color = 'red' | 'green' | 'blue' | 'transparent';
type Solid = Exclude<Color, 'transparent'>; // 'red' | 'green' | 'blue'
type Primary = Extract<Color, 'red' | 'blue' | 'yellow'>; // 'red' | 'blue'
InstanceType<typeof Ctor> and ConstructorParameters<typeof Ctor> work on classes.
class Logger { constructor(public name: string) {} }
type L = InstanceType<typeof Logger>;
type LArgs = ConstructorParameters<typeof Logger>; // [string]
Composing utilities
Real codebases combine them. Suppose you want a “create” type that strips server-generated fields and makes some optional:
type CreateUserInput = Partial<Pick<User, 'age'>> & Omit<User, 'id' | 'age'>;
// { name: string; email: string; age?: number; }
Or a deeply readonly type:
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
That last one is not built in; the standard Readonly is shallow. Writing your own helpers on top of the built-ins is how mature codebases evolve.
Common pitfalls
Omitdoes not enforce that the keys exist on the source. Misspelled keys silently produce the same type. Use a constrained version if you need stricter behavior.Partialis shallow. Nested objects stay required. Combine with aDeepPartialhelper if needed.Recorddefaults to including every key, even ones you did not assign at runtime. Combine withPartial<Record<K, V>>if assignments are optional.ReturnTypeof an overloaded function picks the last overload. Surprising if you rely on the first signature.
Best practices
- Derive types from a single source. Define
Useronce and letPartial,Pick, andOmitproduce variants. - Name derived types meaningfully.
UpdateUserPatchreads better thanPartial<User>everywhere. - Use
satisfies(TypeScript 4.9+) when you want to check shape conformance without losing literal types:
const palette = {
red: '#f00',
blue: '#00f',
} satisfies Record<string, `#${string}`>;
- Prefer composition over deeply nested conditional types unless you really need them. Readability matters more than cleverness.
FAQ
Where are utility types defined? In TypeScript’s lib files (lib.es5.d.ts, lib.esnext.d.ts). You can Cmd-click them in your editor.
Do they have runtime cost? Zero. They are erased at compile time.
Can I make my own? Yes, with generics, conditional types, and mapped types. Look at how the built-ins are written; they are short and instructive.
Is Pick the same as Omit with the complement? Logically yes, but Pick is positive (list what to include) and Omit is negative (list what to exclude). Pick whichever reads better.
Related articles
- TypeScript TypeScript Conditional Types Explained
T extends U ? X : Y, distribution over unions, and the infer keyword — the three rules that build every advanced TypeScript utility.
- TypeScript TypeScript Mapped Types: Readonly, Partial from Scratch
Build Partial, Readonly, Pick, and Record yourself with mapped types, modifier control, and key remapping — the toolkit behind every utility type.
- TypeScript TypeScript Type Narrowing and User-Defined Guards
A practical guide to narrowing in TypeScript — typeof, instanceof, in, discriminated unions, custom predicates with `x is T`, assertion functions, and exhaustive checks with never.
- TypeScript TypeScript Enums and Literal Types
A practical guide to enums and literal types in TypeScript — string enums, number enums, const enums, literal unions as a lighter alternative, and discriminated unions.