Composing Multiple TypeScript Utility Types

Learn how to combine Partial, Pick, Omit, Required, Readonly, and other utility types together for complex real-world type transformations.

Advanced Patterns

Detailed Explanation

Composing Utility Types

The real power of TypeScript's utility types emerges when you combine them. Each utility type performs a single transformation; composing them lets you express complex type requirements concisely.

Pattern: Required-Optional Split

interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
  bio?: string;
}

// Only id is required, everything else is optional
type UserUpdate = Required<Pick<User, "id">> & Partial<Omit<User, "id">>;

Pattern: Immutable Subset

type ReadonlyProfile = Readonly<Pick<User, "id" | "name" | "email">>;
// {
//   readonly id: string;
//   readonly name: string;
//   readonly email: string;
// }

Pattern: Deep Required without Nulls

type StrictUser = Required<{
  [K in keyof User]: NonNullable<User[K]>;
}>;

Pattern: Discriminated Union Actions

type Action =
  | { type: "SET_USER"; payload: User }
  | { type: "SET_LOADING"; payload: boolean }
  | { type: "SET_ERROR"; payload: string };

type ActionPayload<T extends Action["type"]> =
  Extract<Action, { type: T }>["payload"];

type UserPayload = ActionPayload<"SET_USER">;
// Result: User

Pattern: API Response Wrapper

type ApiResponse<T> = {
  data: T;
  status: number;
  headers: Record<string, string>;
};

type PaginatedResponse<T> = ApiResponse<T[]> & {
  total: number;
  page: number;
  pageSize: number;
};

type UserListResponse = PaginatedResponse<
  Pick<User, "id" | "name" | "avatar">
>;

Pattern: Form State

type FormState<T> = {
  values: Partial<T>;
  errors: Partial<Record<keyof T, string>>;
  touched: Partial<Record<keyof T, boolean>>;
  isValid: boolean;
};

type UserForm = FormState<Omit<User, "id">>;

Use Case

Compose utility types when you need complex type transformations that a single utility type cannot express. Common in form state management, API layer typing, Redux action patterns, and creating flexible generic abstractions.

Try It — TypeScript Utility Types

Open full tool