TypeScript Utility Types
Apply built-in TypeScript utility types to transform and compose types without redundancy
When to Use
- You need a variant of an existing type with some properties optional, required, or removed
- You want to derive a type from a function's return value or parameter list without duplicating it
- You need to build a lookup map type from a union of keys
- You want to filter a union type to include or exclude specific members
- You are building form types, API response shapes, or partial update payloads
Instructions
- Use
Partial<T>for optional-update payloads where every field is optional. - Use
Required<T>to make every optional field mandatory (opposite of Partial). - Use
Pick<T, K>to create a type with only the listed keys from T. - Use
Omit<T, K>to create a type with all keys except the listed ones. - Use
Record<K, V>to define a mapping type — prefer over index signatures when keys are known. - Use
Exclude<T, U>to remove union members assignable to U from T. - Use
Extract<T, U>to keep only union members assignable to U. - Use
ReturnType<typeof fn>to derive the return type of a function without manually declaring it. - Use
Parameters<typeof fn>to derive the parameter tuple of a function. - Chain utility types when needed:
Partial<Pick<User, 'name' | 'email'>>.
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'viewer' | 'editor';
createdAt: Date;
}
// Partial update payload — all fields optional
type UserUpdate = Partial<Omit<User, 'id' | 'createdAt'>>;
// Public profile — only safe fields
type PublicUser = Pick<User, 'id' | 'name' | 'role'>;
// Role lookup map
type RoleConfig = Record<User['role'], { canWrite: boolean; canDelete: boolean }>;
// Exclude admin from public-facing role type
type PublicRole = Exclude<User['role'], 'admin'>; // 'viewer' | 'editor'
// Infer return type without coupling to implementation
async function fetchUser(id: string): Promise<User> {
/* ... */ return {} as User;
}
type FetchUserResult = Awaited<ReturnType<typeof fetchUser>>; // User
// Infer parameters for wrapping/mocking
type FetchUserParams = Parameters<typeof fetchUser>; // [id: string]
Details
All utility types are implemented as generic conditional or mapped types in TypeScript's standard library (lib.es5.d.ts). Understanding their implementation helps you build custom variants when the built-ins don't cover your case.
Implementation anatomy
// Partial<T> implementation
type Partial<T> = { [P in keyof T]?: T[P] };
// Pick<T, K> implementation
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
// Exclude<T, U> implementation
type Exclude<T, U> = T extends U ? never : T;
// ReturnType<T> implementation
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
Omit vs Exclude
Omit<T, K> operates on object types and removes properties. Exclude<T, U> operates on union types and removes members. They are not interchangeable.
Record vs index signatures
Record<string, V> and { [key: string]: V } are equivalent for most purposes, but Record<K, V> with a union K creates a required entry for each union member — the index signature does not.
Composing utility types
Utility types compose via nesting. Deep transformations may require recursive types (TypeScript 4.1+) or a custom mapped type. For deeply partial types, the standard library's Partial only goes one level deep.
NonNullable<T>
Removes null and undefined from a type. Equivalent to Exclude<T, null | undefined>. Useful after null-safety guards.
ConstructorParameters<T> and InstanceType<T>
Less common but useful for class-based code: ConstructorParameters extracts the constructor's args, InstanceType extracts what new T() produces.
When to write custom utilities instead
When none of the built-ins express your transformation, write a mapped or conditional type. The built-ins are a starting point, not a ceiling.
Source
https://typescriptlang.org/docs/handbook/utility-types.html
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.