Quick take: - TypeScript ships with utility types that transform existing types without rewriting them. The most useful ones are Partial, Required, Pick, Omit, Record, Exclude, and Extract. Per the TypeScript Handbook, these are globally available in TypeScript 4.x and 5.x with no imports needed, usage is covered here, patterns is covered here.
TypeScript's built-in utility types cover 90% of real-world type transformation needs. Partial<T> makes all properties optional (used for PATCH payloads and form drafts). Required<T> makes all properties mandatory (used after validation). Pick<T, K> creates a type with only the listed keys; Omit<T, K> creates a type with those keys removed, use Pick for small subsets, Omit when removing one or two fields from a large interface. Record<K, V> creates a typed object where all keys share one value type, and TypeScript flags missing keys at compile time when the key is a union. Exclude<T, U> removes members from a union; Extract<T, U> keeps only matching members. All seven are globally available since TypeScript 2.x with no import statement. They compose freely: Partial<Pick<User, 'name' | 'email'>> is a valid, readable pattern.
Utility types are one of those TypeScript features that you don't appreciate until the day you stop duplicating interfaces everywhere. I've worked on codebases where every form, every API payload, and every partial update had its own hand-written type. It's tedious. Worse, those types drift apart over time.
What Are TypeScript Utility Types?
TypeScript's built-in utility types are generic types that transform other types. They're available globally in TypeScript 2.8+ (Exclude, Extract) and TypeScript 2.1+ (Partial, Required, Pick, Omit). No import statement needed. They do the kind of type manipulation that you'd otherwise write with mapped types and generics by hand.
The short list you'll use every week: Partial<T>, Required<T>, Pick<T, K>, Omit<T, K>, Record<K, T>, Exclude<T, U>, and Extract<T, U>.
How Does Partial Work?
Partial<T> makes every property of T optional. The most common use case is update payloads, where you only send the fields that changed.
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'editor' | 'viewer';
}
// All fields are now optional
type UserUpdate = Partial<User>;
async function updateUser(id: string, changes: UserUpdate) {
return fetch(`/api/users/${id}`, {
method: 'PATCH',
body: JSON.stringify(changes),
});
}
// TypeScript accepts any subset of fields
await updateUser('u-1', { name: 'Alice' });
await updateUser('u-1', { role: 'admin', email: '[email protected]' });
In our experience, Partial<T> is most valuable in PATCH endpoints and form-state types. Without it, you'd write a second interface with ? on every field.
How Does Required Work?
Required<T> is the inverse. It removes all ? marks, making every optional property mandatory.
interface Config {
apiUrl?: string;
timeout?: number;
retries?: number;
}
// After loading + validation, every field must be present
type ResolvedConfig = Required<Config>;
function validateConfig(raw: Config): ResolvedConfig {
if (!raw.apiUrl) throw new Error('apiUrl is required');
return {
apiUrl: raw.apiUrl,
timeout: raw.timeout ?? 5000,
retries: raw.retries ?? 3,
};
}
The return type of validateConfig guarantees callers that all fields are safe to access without null checks.
How Do Pick and Omit Shape Interfaces?
Pick<T, K> selects a subset of keys. Omit<T, K> removes specific keys. Both create new types derived from an existing one.
interface Product {
id: string;
name: string;
price: number;
stock: number;
createdAt: Date;
updatedAt: Date;
}
// Only expose what the UI needs
type ProductCard = Pick<Product, 'id' | 'name' | 'price'>;
// Strip internal timestamps from the public API response
type PublicProduct = Omit<Product, 'createdAt' | 'updatedAt'>;
Which should you use? Pick is better when the subset is small. Omit is better when you're removing one or two fields from a large interface. If you find yourself listing 8 fields in a Pick, switch to Omit.
Combining Pick and Partial for Form State
This pattern shows up in almost every form I write:
// Full user type
interface User {
id: string;
name: string;
email: string;
bio: string;
}
// Editable fields only, all optional for draft state
type ProfileDraft = Partial<Pick<User, 'name' | 'email' | 'bio'>>;
The type says exactly what it means: a draft profile edit where any combination of name, email, or bio can be present.
How Does Record Work?
Record<K, V> creates an object type where all keys are of type K and all values are of type V. It's the typed alternative to { [key: string]: SomeType }.
type HttpStatus = 200 | 201 | 400 | 401 | 403 | 404 | 500;
const statusMessages: Record<HttpStatus, string> = {
200: 'OK',
201: 'Created',
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
500: 'Internal Server Error',
};
// TypeScript ensures every HttpStatus key is present
// Adding a new status to HttpStatus forces you to add a message too
Using a union as the key type is where Record really shines. TypeScript will flag missing keys at compile time.
What Do Exclude and Extract Do?
These work on union types, not object types. That distinction trips people up.
type Status = 'active' | 'inactive' | 'pending' | 'banned';
// Remove specific members from the union
type ActiveStatus = Exclude<Status, 'banned' | 'inactive'>;
// Result: 'active' | 'pending'
// Keep only the members that match
type ClosedStatus = Extract<Status, 'inactive' | 'banned'>;
// Result: 'inactive' | 'banned'
A practical use: filtering out null and undefined from a union.
type MaybeString = string | null | undefined;
type DefiniteString = Exclude<MaybeString, null | undefined>;
// Result: string
TypeScript 2.8 actually uses Exclude to implement NonNullable<T> internally. So NonNullable<T> is just Exclude<T, null | undefined> under the hood.
Which Utility Types Should I Learn First?
Start with Partial and Pick. You'll use them on day one. Then add Omit and Record. Save Exclude and Extract for when you start working with complex union manipulation.
Don't try to memorize the full list. TypeScript 5.x ships around 20 utility types. Most of them are useful occasionally. The seven covered here cover 90% of real cases.
Related
- TypeScript Generics: A Practical Guide for React Developers - utility types are built from generic mapped types; understanding generics helps you build your own utilities
- TypeScript 7 (Project Corsa) guide - the native Go compiler type-checks deeply nested utility type chains 10x faster; the overview explains what changed at the July 2026 GA
- TypeScript 7 migration - the step-by-step upgrade, worth reading before you lean into
Pick,Omit, and conditional types at scale - Node.js 20 to 24 migration -
@types/nodeships updated utility-compatible types for new Node.js globals likeReadableStreamandfetch; upgrading Node changes which types you need - React Hooks pitfalls - use
Partial<T>andPick<T, K>to type hook return values and state objects cleanly