TypeScript Utility Types: The Practical Reference
TypeScript ships with a library of built-in utility types that transform existing types. Instead of duplicating type definitions, these let you derive new types from existing ones — reducing maintenance burden and keeping your codebase DRY.
Object Transformation Types
Partial<T>
Makes all properties optional.
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
}
// All fields optional — useful for update payloads
type UserUpdate = Partial<User>;
function updateUser(id: number, changes: Partial<User>) {
// changes can have any subset of User fields
}
updateUser(1, { name: 'Alice' }); // ✅
updateUser(1, { email: 'a@b.com', role: 'admin' }); // ✅
Required<T>
Makes all properties required (opposite of Partial).
interface Config {
timeout?: number;
retries?: number;
baseUrl?: string;
}
// All fields required after initialization
type ResolvedConfig = Required<Config>;
function resolveConfig(input: Config): ResolvedConfig {
return {
timeout: input.timeout ?? 5000,
retries: input.retries ?? 3,
baseUrl: input.baseUrl ?? 'https://api.example.com',
};
}
Readonly<T>
Makes all properties read-only (cannot be reassigned).
const config: Readonly<Config> = {
timeout: 5000,
retries: 3,
baseUrl: 'https://api.example.com',
};
config.timeout = 1000; // ❌ Error: Cannot assign to 'timeout' (read-only)
Pick<T, K>
Creates a type with only the selected keys.
interface User {
id: number;
name: string;
email: string;
passwordHash: string;
createdAt: Date;
}
// Public-facing user — exclude sensitive fields
type PublicUser = Pick<User, 'id' | 'name' | 'email'>;
// Type: { id: number; name: string; email: string }
function getPublicProfile(user: User): PublicUser {
return { id: user.id, name: user.name, email: user.email };
}
Omit<T, K>
Creates a type with the specified keys removed.
// Remove sensitive and auto-generated fields for creation input
type CreateUserInput = Omit<User, 'id' | 'passwordHash' | 'createdAt'>;
// Type: { name: string; email: string }
function createUser(input: CreateUserInput): User {
return {
...input,
id: generateId(),
passwordHash: hashPassword(input.email),
createdAt: new Date(),
};
}
Pick vs Omit: Use Pick when you want a small subset of a large type. Use Omit when you want most of a type except a few fields.
Record<K, V>
Creates an object type with keys of type K and values of type V.
// Map from string keys to numbers
type ScoreMap = Record<string, number>;
const scores: ScoreMap = { alice: 95, bob: 87 };
// Map enum values to config objects
type EnvironmentConfig = Record<'dev' | 'staging' | 'prod', {
apiUrl: string;
debug: boolean;
}>;
const envConfig: EnvironmentConfig = {
dev: { apiUrl: 'http://localhost:3000', debug: true },
staging: { apiUrl: 'https://staging.api.example.com', debug: true },
prod: { apiUrl: 'https://api.example.com', debug: false },
};
// More constrained: key must be a valid HTTP method
type HttpMethodHandlers = Record<'GET' | 'POST' | 'PUT' | 'DELETE', Function>;
Union/Intersection Type Helpers
Exclude<T, U>
Removes types from a union that are assignable to U.
type Status = 'pending' | 'active' | 'deleted' | 'banned';
// Remove administrative statuses
type UserFacingStatus = Exclude<Status, 'deleted' | 'banned'>;
// Type: 'pending' | 'active'
type NonNullableString = Exclude<string | null | undefined, null | undefined>;
// Type: string
Extract<T, U>
Keeps only types from a union that are assignable to U (opposite of Exclude).
type Events = 'click' | 'focus' | 'blur' | 'keydown' | 'keyup';
// Only keyboard events
type KeyboardEvents = Extract<Events, 'keydown' | 'keyup' | 'keypress'>;
// Type: 'keydown' | 'keyup'
// Extract object types from a union
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } | string;
type ShapeObject = Extract<Shape, object>;
// Type: { kind: 'circle'; radius: number } | { kind: 'square'; side: number }
NonNullable<T>
Removes null and undefined from a type.
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// Type: string
function processName(name: string | null): string {
const safe: NonNullable<typeof name> = name ?? 'Anonymous';
return safe.toUpperCase();
}
Function-Related Types
ReturnType<T>
Extracts the return type of a function type.
function fetchUser(id: number) {
return { id, name: 'Alice', email: 'alice@example.com' };
}
type FetchedUser = ReturnType<typeof fetchUser>;
// Type: { id: number; name: string; email: string }
// Works with async functions too
async function getConfig() {
return { timeout: 5000, debug: false };
}
type Config = Awaited<ReturnType<typeof getConfig>>;
// Type: { timeout: number; debug: boolean }
// Note: Awaited unwraps the Promise
Parameters<T>
Extracts function parameters as a tuple type.
function createEvent(name: string, date: Date, attendees: number) {
// ...
}
type CreateEventParams = Parameters<typeof createEvent>;
// Type: [name: string, date: Date, attendees: number]
// Useful for wrapper functions
function createEventWithLogging(...args: Parameters<typeof createEvent>) {
console.log('Creating event:', args[0]);
return createEvent(...args);
}
ConstructorParameters<T>
Extracts constructor parameters.
class HttpClient {
constructor(baseUrl: string, timeout: number, headers: Record<string, string>) {}
}
type ClientConfig = ConstructorParameters<typeof HttpClient>;
// Type: [baseUrl: string, timeout: number, headers: Record<string, string>]
InstanceType<T>
Extracts the instance type of a constructor.
class ApiClient {
get(url: string) { return fetch(url); }
post(url: string, body: unknown) { return fetch(url, { method: 'POST' }); }
}
type Client = InstanceType<typeof ApiClient>;
// Type: ApiClient
// Useful with factory patterns
function createClient(): InstanceType<typeof ApiClient> {
return new ApiClient();
}
Combining Utility Types
Real-world types often combine multiple utilities:
interface Article {
id: string;
title: string;
content: string;
authorId: string;
publishedAt: Date;
updatedAt: Date;
tags: string[];
}
// Input for creating: no auto-generated fields
type CreateArticleInput = Omit<Article, 'id' | 'publishedAt' | 'updatedAt'>;
// Input for updating: all fields optional except id
type UpdateArticleInput = Partial<Omit<Article, 'id'>> & Pick<Article, 'id'>;
// Article preview: only display fields
type ArticlePreview = Pick<Article, 'id' | 'title' | 'authorId' | 'publishedAt' | 'tags'>;
// Deep partial (utility types don't go deep by default)
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
Template Literal Types (Advanced)
// Generate event handler names from event names
type EventNames = 'click' | 'focus' | 'blur';
type HandlerNames = `on${Capitalize<EventNames>}`;
// Type: 'onClick' | 'onFocus' | 'onBlur'
// Generate getter/setter pairs
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface User { name: string; age: number; }
type UserGetters = Getters<User>;
// Type: { getName: () => string; getAge: () => number }
Quick Reference
| Utility Type | What it does |
|---|---|
Partial<T> |
All props optional |
Required<T> |
All props required |
Readonly<T> |
All props read-only |
Pick<T, K> |
Keep only K keys |
Omit<T, K> |
Remove K keys |
Record<K, V> |
Object with K keys and V values |
Exclude<T, U> |
Remove U from union T |
Extract<T, U> |
Keep only U in union T |
NonNullable<T> |
Remove null/undefined |
ReturnType<T> |
Function return type |
Parameters<T> |
Function parameter types |
Awaited<T> |
Unwrap Promise type |
→ View and explore complex JSON data structures with the JSON Viewer.