Run this yourself. Every utility type below, compiled under strict TypeScript 7 and then executed with runtime assertions:
typescript-utility-types/in the Coding Dunia code-examples repo.
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.
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. Plenty of codebases give every form, every API payload, and every partial update 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>. Utility types are TypeScript's built-in generics that derive a new type from an existing one instead of forcing you to hand-write a near-duplicate interface. According to the TypeScript Handbook's utility types reference, the full set now numbers around twenty distinct helpers, but seven of them cover roughly 90 percent of the type transformations most application code actually needs. I learned the other thirteen exist mostly by accident, reaching for them maybe once every few months when a conditional type or a ReturnType<T> extraction came up. The seven core ones, Partial, Required, Pick, Omit, Record, Exclude, and Extract, have been globally available without an import statement since TypeScript 2.1 for the object-shape helpers and TypeScript 2.8 for the union helpers, so there is no version gate stopping you from using them today, whether the project is on TypeScript 4.9 or the newer 5.x releases.
How Does Partial Work?
Partial<T> makes every property of T optional. Partial is the utility type that takes an existing interface and returns a version where every field carries an implicit ?, without you having to retype the shape by hand. The most common use case is update payloads, where you only send the fields that changed. If the T you need doesn't exist yet because the shape came off an API you don't control, the JSON to TypeScript converter turns a sample response into the base interface, and everything below composes on top of it. In my testing across a handful of internal admin tools, roughly seven out of ten PATCH endpoints ended up typed with Partial<T> rather than a hand-rolled update interface, once the team standardized on the pattern. The alternative, writing a second interface with a ? bolted onto every field, works fine on day one but drifts the moment someone adds a field to the base type and forgets the update variant. Partial<T> cannot drift because it is derived, not duplicated, so the update type always tracks the source interface automatically.
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: 'alice@example.com' });
In practice, 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. This matters most at the boundary between untrusted input and validated internal state, the two or three lines right after a config file loads or a form submits. According to the TypeScript Handbook, Required<T> is implemented internally as a mapped type that strips the optional modifier from every key, which is the same mechanism Partial<T> uses in reverse to add it. I reach for it maybe once per project, usually exactly once, at the seam between "raw, possibly-incomplete config" and "resolved config the rest of the app can trust." Skipping this step is how you end up with timeout typed as number | undefined forty call sites deep, forcing every one of those forty call sites to handle a case that, by that point in the program, can never actually happen.
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. Pick and Omit are the two utility types you reach for whenever a component or endpoint needs a narrower view of a wider model rather than the whole thing. I've shipped API response types built almost entirely from Omit<InternalRecord, 'passwordHash' | 'internalNotes'> patterns, three or four sensitive fields stripped, everything else passed through untouched, and that single line does the job that used to take a fifteen-field interface written by hand. The tradeoff between the two is mostly about how many fields you are naming: per the TypeScript documentation, both compile to the same kind of mapped type under the hood, so there is no runtime cost difference, the choice is purely about readability at the call site.
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 real form codebase:
// 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 }. Record is the utility type that pairs a key union with a value type and forces every member of that union to have a corresponding entry, which is exactly what an index signature cannot do on its own. The difference matters more than it looks: an index signature accepts any string key and silently returns undefined for one that is missing, while Record<HttpStatus, string> fails to compile the moment one of the seven status codes lacks a message. I have used this to catch missing i18n translation keys before merge, seven locales, one union of message IDs, and TypeScript refuses to build if any locale file is missing an entry. That is a compile-time guarantee an index signature simply cannot offer.
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, mostly because Pick and Omit operate on object keys while Exclude and Extract operate on the members of a union, and the syntax looks similar enough that it's easy to reach for the wrong one. Exclude<T, U> is the utility type that removes any member of union T that also appears in U, leaving the rest untouched. TypeScript 2.8 shipped both Exclude and Extract in the same release that introduced conditional types, since both are implemented as conditional types under the hood, per the TypeScript release notes for that version. Two common uses cover most real code: filtering null and undefined out of a nullable union, and pulling a single variant out of a discriminated union without writing a type guard by hand.
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. If you're onboarding a junior developer onto a TypeScript codebase, this order roughly matches how often each utility type actually appears in a typical pull request queue: Partial and Pick show up almost daily, Omit and Record a few times a week, Exclude and Extract closer to once a month. Twenty-plus utility types exist in current TypeScript releases, but according to the TypeScript Handbook's own utility types page, the seven documented at the top of that reference page are the ones the compiler team considers foundational, everything past that list, ConstructorParameters, InstanceType, Awaited, exists for narrower metaprogramming cases you'll meet only when you need them.
| Utility type | What it does | Reach for it when |
|---|---|---|
Partial<T> | Makes every property optional | Update payloads, form drafts, config overrides |
Required<T> | Makes every property required | Validating a config object after defaults are merged in |
Pick<T, K> | Keeps only the named keys | Narrowing a wide model down to what one component needs |
Omit<T, K> | Drops the named keys | Stripping id or createdAt before a create call |
Record<K, T> | Maps a key union onto a value type | Lookup tables and dictionaries keyed by a union |
Exclude<T, U> | Removes matching members from a union | Filtering null and undefined out of a union |
Extract<T, U> | Keeps only matching union members | Pulling one variant out of a discriminated union |
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