Frontend Patterns

Pattern

Utility Type

Leverage built-in or custom utility types to transform and manipulate types.

Utility Type

Problem

Types are duplicated across the codebase with manual modifications, creating drift when the original type changes. Developers manually mark all fields as optional for partial updates, manually remove readonly modifiers for internal mutations, or manually extract specific properties into new interfaces. These manual type transformations become outdated, leading to type mismatches and maintenance burden.

Solution

Use TypeScript’s built-in utility types to transform existing types in common ways. This reduces boilerplate and makes type manipulations more expressive.

Example

This demonstrates using TypeScript’s built-in utility types to transform existing types in common ways, reducing boilerplate and keeping derived types in sync with source types automatically.

type User = { id: number; name: string; email: string };

// Pick specific properties for a subset type
type UserPreview = Pick<User, 'id' | 'name'>; // { id: number; name: string }

// Make all properties optional for partial updates
type PartialUser = Partial<User>;

// Make all properties required (useful after Partial)
type RequiredUser = Required<PartialUser>;

Benefits

  • Reduces boilerplate by reusing type transformation logic.
  • Makes type transformations self-documenting and standardized.
  • Keeps derived types in sync with source types automatically.
  • Provides expressive, composable type transformations.

Tradeoffs

  • Requires understanding TypeScript’s utility type library.
  • Can create complex types that are hard to read and debug.
  • Error messages become less clear with nested utility types.
  • May need custom utility types for domain-specific transformations.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.