TypeScript Utility Types: Partial, Pick, Omit, Record, and Custom...
TypeScript ships with a comprehensive set of built-in utility types that transform existing types into new ones. These utilities reduce boilerplate, enforce consistency, and eliminate manual type duplication. Understanding them is essential for productive TypeScript development — they appear in virtually every production codebase. The TypeScript Handbook documents each utility type with examples (see TypeScript Utility Types). This guide covers every built-in utility type, explains its implementation using mapped/conditional types, and demonstrates advanced compositions.
Property Modification Utilities
Partial<T>
Partial<T> makes all properties in T optional. It is implemented as a mapped type:
type Partial<T> = {
[P in keyof T]?: T[P];
---;Use Partial for update operations where only a subset of fields is provided. Combined with the Pick utility, it enables precise API contract definitions:
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
---
type UpdateUserPayload = Partial<Omit<User, 'id'>>;
// { name?: string; email?: string; role?: 'admin' | 'user' }
Required<T>
Required<T> is the inverse of Partial — it makes all properties required by removing the ? modifier:
type Required<T> = {
[P in keyof T]-?: T[P];
---;The -? syntax strips the optional modifier. Use Required when accepting a potentially partial input but needing a complete object internally:
interface Config {
url?: string;
timeout?: number;
retries?: number;
---
function normalizeConfig(config: Config): Required<Config> {
return {
url: config.url ?? 'https://default.api',
timeout: config.timeout ?? 5000,
retries: config.retries ?? 3,
};
---The Required type ensures consumers of normalizeConfig always receive a fully populated configuration object without needing runtime checks.
Readonly<T>
Readonly<T> adds the readonly modifier to all properties, preventing reassignment after construction:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
---;Use for immutable data models, configuration objects, and state snapshots.
Property Selection Utilities
Pick<T, K>
Pick<T, K> creates a type by selecting a subset of properties K from T:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
---;type UserPreview = Pick<User, 'name' | 'email'>;
// { name: string; email: string; }
Omit<T, K>
Omit<T, K> is the complement of Pick — it creates a type excluding the properties in K:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;type UserWithoutId = Omit<User, 'id'>;
// { name: string; email: string; role: 'admin' | 'user' }
Pick and Omit are the most frequently used utility types. They model projections of database entities, API response shaping, and component prop subsets.
Composition Utilities
Record<K, T>
Record<K, T> creates an object type with keys of type K and values of type T:
type Record<K extends keyof any, T> = {
[P in K]: T;
---;type PageRoutes = Record<'home' | 'about' | 'contact', string>;
// { home: string; about: string; contact: string; }
Record is ideal for lookup tables, enums with associated data, and configuration maps:
const errorMessages: Record<number, string> = {
404: 'Not Found',
500: 'Internal Server Error',
---;Union Filtering Utilities
Exclude<T, U>
Exclude<T, U> removes types from a union that are assignable to U:
type Exclude<T, U> = T extends U ? never : T;Because this is a conditional type on a bare type parameter, it distributes over T. If T is string | number | boolean and U is string, the result is number | boolean.
Extract<T, U>
Extract<T, U> is the complement — it keeps only the types in T that are assignable to U:
type Extract<T, U> = T extends U ? T : never;type Numbers = Extract<string | number | boolean, number | string>;
// string | number
NonNullable<T>
NonNullable<T> removes null and undefined from a type:
type NonNullable<T> = T extends null | undefined ? never : T;type T0 = NonNullable<string | number | undefined>; // string | number
Function Type Utilities
Parameters<T>
Parameters<T> extracts the parameter types of a function type as a tuple:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;function greet(name: string, age: number): void {}
type GreetParams = Parameters<typeof greet>; // [string, number]
This utility is invaluable for wrapping functions while preserving their argument types. For example, creating a debounced version of any function:
function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timer: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
---The Parameters<T> utility ensures the debounced function has the exact same type signature as the original, without manual overloads.
ReturnType<T>
ReturnType<T> extracts the return type of a function type:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : never;type GreetReturn = ReturnType<typeof greet>; // void
ConstructorParameters<T> and InstanceType<T>
These mirror Parameters and ReturnType but for constructor functions:
class User { constructor(public id: number, public name: string) {} }
type UserParams = ConstructorParameters<typeof User>; // [number, string]
type UserInstance = InstanceType<typeof User>; // User
These utilities enable factory patterns and dependency injection systems to work with constructor types generically without losing type information.
Promise Utilities
Awaited<T>
Awaited<T> recursively unwraps Promise types. It is the type equivalent of await:
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;type Result = Awaited<Promise<Promise<string>>>; // string
Useful for typing async function results without manual unwrapping:
type FetchResult = Awaited<ReturnType<typeof fetchData>>;Template Literal and String Manipulation Utilities
TypeScript 4.1 introduced intrinsic string manipulation types: Uppercase<S>, Lowercase<S>, Capitalize<S>, and Uncapitalize<S>. These operate at the type level for converting string literal types:
type EventName = 'click' | 'focus';
type HandlerName = `on${Capitalize<EventName>}`; // 'onClick' | 'onFocus'
Event Handler Patterns
Combining template literal types with mapped types creates type-safe event systems:
type Events = 'userLogin' | 'userLogout' | 'error';
type EventHandlers = {
[K in Events as `on${Capitalize<K>}`]: (payload: unknown) => void;
---;
// { onUserLogin: (payload: unknown) => void; onUserLogout: ... }
This pattern is used extensively in libraries like tRPC, Prisma, and EventEmitter3 to generate type-safe handler registrations from string union definitions.
Creating Custom Utility Types
Combining mapped types, conditional types, and key remapping (TypeScript 4.1+) enables custom utilities:
DeepPartial<T>
Makes all nested properties optional recursively:
type DeepPartial<T> = T extends object
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;PickByType<T, V>
Picks properties whose values match a given type:
type PickByType<T, V> = {
[P in keyof T as T[P] extends V ? P : never]: T[P];
---;
type StringProps = PickByType<{ name: string; age: number; email: string }, string>;
// { name: string; email: string; }
NonFunctionKeys<T>
Extracts property keys that are not functions:
type NonFunctionKeys<T> = {
[P in keyof T]: T[P] extends Function ? never : P;
---[keyof T];Indexed access ([keyof T]) converts the mapped object into a union of its value types, filtering out keys where the value was never.
UnionToIntersection<T>
Converts a union to an intersection — useful for merging overloaded types:
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends
(k: infer I) => void ? I : never;
type Result = UnionToIntersection<{ a: string } | { b: number }>;
// { a: string } & { b: number }
This uses the contravariant position trick: in a union ((k: A) => void) | ((k: B) => void), the parameter in a contravariant position becomes A & B.
FAQ
What is the difference between Omit and Exclude?Omit works on object types, removing specified keys. Exclude works on union types, removing specified members. Omit<User, 'id'> removes the id property; Exclude<string | number, string> removes string from the union.
Can I use utility types with classes?
Yes. Utility types work with class types the same way they work with interfaces and object type aliases. Partial<MyClass> makes all class properties optional.
How do I make a type that picks properties by value type?
Use PickByType<T, V> (shown above) or KeysByType<T, V> to get just the keys, then Pick.
What does keyof any mean in Record’s definition?keyof any resolves to string | number | symbol — the set of valid object keys. It constrains K to valid property keys.
Are utility types available at runtime?
No. Utility types are pure type-system constructs and are erased during compilation. They have zero runtime overhead.