TypeScript Utility Types Cheat Sheet: Pick, Omit, Partial and More
On this page
I keep coming back to this reference myself. TypeScript's built-in utility types are incredibly powerful — they let you transform types without writing them from scratch. But the official docs are... not great at showing you when you'd actually use them. So here's the cheat sheet I wish I'd had when I started with TypeScript, with real code from real projects.
TL;DR: A practical reference for TypeScript utility types with real-world examples. Master Pick, Omit, Partial, Required, Record, and more.
The Setup: A Base Type
I'll use this User type throughout — it's the kind of thing you'd find in any web app:
interface User {
id: string;
email: string;
name: string;
avatar: string | null;
role: 'admin' | 'editor' | 'viewer';
createdAt: Date;
updatedAt: Date;
}
Partial<T>
Makes all properties optional. Essential for update operations where you only send changed fields.
type UpdateUserInput = Partial<User>;
// Equivalent to:
// {
// id?: string;
// email?: string;
// name?: string;
// avatar?: string | null;
// role?: 'admin' | 'editor' | 'viewer';
// createdAt?: Date;
// updatedAt?: Date;
// }
async function updateUser(id: string, data: Partial<User>) {
return db.user.update({ where: { id }, data });
}
// Usage: only send what changed
await updateUser('123', { name: 'New Name' }); // valid
await updateUser('123', { role: 'admin' }); // valid
await updateUser('123', {}); // also valid (no changes)
Required<T>
The opposite of Partial. Makes all properties required, even if they were optional in the original type.
interface Config {
apiUrl?: string;
timeout?: number;
retries?: number;
}
type ResolvedConfig = Required<Config>;
// Now all properties are required:
// {
// apiUrl: string;
// timeout: number;
// retries: number;
// }
function initApp(config: ResolvedConfig) {
// No need to check for undefined values
fetch(config.apiUrl, { signal: AbortSignal.timeout(config.timeout) });
}
Pick<T, K>
Creates a type with only the specified properties. Use it to create focused types for specific use cases.
type UserPreview = Pick<User, 'id' | 'name' | 'avatar'>;
// {
// id: string;
// name: string;
// avatar: string | null;
// }
function renderUserCard(user: UserPreview) {
return `<div>${user.name}</div>`;
}
// You can pass a full User object — it satisfies UserPreview
const fullUser: User = { /* ... */ };
renderUserCard(fullUser); // works fine
Omit<T, K>
Creates a type with all properties except the specified ones. The inverse of Pick.
type CreateUserInput = Omit<User, 'id' | 'createdAt' | 'updatedAt'>;
// {
// email: string;
// name: string;
// avatar: string | null;
// role: 'admin' | 'editor' | 'viewer';
// }
async function createUser(input: CreateUserInput): Promise<User> {
return db.user.create({
data: {
...input,
id: crypto.randomUUID(),
createdAt: new Date(),
updatedAt: new Date(),
},
});
}
Pro tip: Prefer Omit over Pick when you want "everything except a few fields". It is more maintainable because adding new fields to the base type automatically includes them.
Record<K, V>
Creates an object type with keys of type K and values of type V. Extremely useful for dictionaries and lookup maps.
type UserRole = 'admin' | 'editor' | 'viewer';
const rolePermissions: Record<UserRole, string[]> = {
admin: ['read', 'write', 'delete', 'manage-users'],
editor: ['read', 'write'],
viewer: ['read'],
};
// Also great for API response caching
type Cache = Record<string, { data: unknown; expiresAt: number }>;
const cache: Cache = {};
cache['/api/users'] = {
data: users,
expiresAt: Date.now() + 60_000,
};
Readonly<T>
Makes all properties read-only. The compiler will error if you try to reassign them.
type ImmutableUser = Readonly<User>;
function processUser(user: ImmutableUser) {
user.name = 'Changed'; // Error: Cannot assign to 'name' because it is a read-only property
}
// Commonly used with configuration objects
const appConfig: Readonly<Config> = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3,
};
Warning: Readonly is shallow. Nested objects are still mutable. For deep immutability, use a recursive type or a library.
Exclude<T, U>
Removes types from a union. Works on union types, not object properties (that is Omit).
type AllRoles = 'admin' | 'editor' | 'viewer' | 'superadmin';
type PublicRoles = Exclude<AllRoles, 'admin' | 'superadmin'>;
// 'editor' | 'viewer'
// Practical: filter out null/undefined from a union
type MaybeString = string | null | undefined;
type DefinitelyString = Exclude<MaybeString, null | undefined>;
// string
Extract<T, U>
The opposite of Exclude. Keeps only the types that match.
type AllEvents = 'click' | 'scroll' | 'keydown' | 'keyup' | 'focus' | 'blur';
type KeyboardEvents = Extract<AllEvents, 'keydown' | 'keyup'>;
// 'keydown' | 'keyup'
// Extract specific types from a union
type ApiResponse = string | number | { error: string } | null;
type ObjectResponses = Extract<ApiResponse, object>;
// { error: string }
NonNullable<T>
Removes null and undefined from a type. A shorthand for Exclude<T, null | undefined>.
type MaybeUser = User | null | undefined;
type DefiniteUser = NonNullable<MaybeUser>;
// User
// Common in function parameters
function processUser(user: NonNullable<typeof currentUser>) {
// user is guaranteed to be defined here
console.log(user.name);
}
ReturnType<T>
Extracts the return type of a function. Invaluable when working with third-party libraries.
function fetchUser(id: string) {
return {
id,
name: 'John',
email: '[email protected]',
permissions: ['read', 'write'] as const,
};
}
type FetchUserResult = ReturnType<typeof fetchUser>;
// {
// id: string;
// name: string;
// email: string;
// permissions: readonly ['read', 'write'];
// }
// Works with async functions too
async function fetchUsers() {
const response = await fetch('/api/users');
return response.json() as Promise<User[]>;
}
type FetchUsersResult = Awaited<ReturnType<typeof fetchUsers>>;
// User[]
Parameters<T>
Extracts the parameter types of a function as a tuple.
function createOrder(
userId: string,
items: { productId: string; quantity: number }[],
couponCode?: string
) {
// ...
}
type CreateOrderParams = Parameters<typeof createOrder>;
// [string, { productId: string; quantity: number }[], string?]
// Access individual parameters
type OrderItems = Parameters<typeof createOrder>[1];
// { productId: string; quantity: number }[]
Combining Utility Types
The real power comes from composing these types together:
// API input: pick specific fields and make them all optional
type UpdateProfileInput = Partial<Pick<User, 'name' | 'avatar'>>;
// { name?: string; avatar?: string | null; }
// Create input: omit auto-generated fields, then make avatar optional
type CreateUserInput = Omit<User, 'id' | 'createdAt' | 'updatedAt'> & {
avatar?: string | null;
};
// API response: user with computed fields
type UserWithStats = User & {
postCount: number;
lastLogin: Date | null;
};
// Form state: all fields as strings for form inputs
type UserFormState = Record<keyof Pick<User, 'name' | 'email'>, string>;
// { name: string; email: string; }
Quick Reference Table
Partial<T> — All properties become optional
Required<T> — All properties become required
Pick<T, K> — Keep only specified properties
Omit<T, K> — Remove specified properties
Record<K, V> — Create object type with key type K and value type V
Readonly<T> — All properties become read-only
Exclude<T, U> — Remove types from a union
Extract<T, U> — Keep only matching types from a union
NonNullable<T> — Remove null and undefined
ReturnType<T> — Get function return type
Parameters<T> — Get function parameter types as tuple
Awaited<T> — Unwrap Promise type
Key Takeaways
- Use
Partialfor update operations,Omitfor create operations - Prefer
OmitoverPickwhen you want "everything except a few fields" Excludeworks on unions,Omitworks on object types — do not confuse themReadonlyis shallow — nested objects remain mutable- Compose utility types to build exactly the type you need without repetition
Sources
Related Articles
How to Debug Node.js Memory Leaks (Step-by-Step Guide)
Learn how to detect, diagnose, and fix Node.js memory leaks using heap snapshots, Chrome DevTools, and clinic.js — with real code examples.
Building an AI Chatbot With LangChain: Practical Developer Guide
Build a production-ready AI chatbot with LangChain, Python, and OpenAI. Step-by-step guide with memory, RAG, streaming, and deployment tips.
How to Fix CORS Errors in Node.js and Express (Complete Guide)
Master CORS errors in Express. Learn what causes them, how to fix them, and best practices for production APIs with practical examples.