typescript

TypeScript Utility Type Patterns

Common TypeScript utility types for everyday development: DeepPartial, RequireAtLeastOne, and more.

#types #generics #patterns

A collection of useful utility types that extend TypeScript’s built-in utilities.

DeepPartial

Makes all properties optional recursively:

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// Usage
interface Config {
  server: { host: string; port: number };
  features: { dark: boolean };
}

const partial: DeepPartial<Config> = { 
  server: { port: 3000 } // host is optional
};

RequireAtLeastOne

Requires at least one property from a set:

type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<T, Exclude<keyof T, Keys>> &
  { [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys];

// Usage
interface Search {
  query?: string;
  tags?: string[];
  author?: string;
}

type ValidSearch = RequireAtLeastOne<Search, 'query' | 'tags'>;
// Must have either query or tags (or both)

NonNullableFields

Makes specified fields non-nullable:

type NonNullableFields<T, K extends keyof T> = T & {
  [P in K]-?: NonNullable<T[P]>;
};

// Usage
interface User {
  id: string;
  email: string | null;
  name: string | null;
}

type VerifiedUser = NonNullableFields<User, 'email'>;
// email is now required and non-null

Prettify

Flattens intersected types for better IntelliSense:

type Prettify<T> = { [K in keyof T]: T[K] } & {};

// Usage
type Combined = { a: string } & { b: number };
type Pretty = Prettify<Combined>;
// Shows { a: string; b: number } instead of intersection

StrictOmit

Omit that enforces valid keys:

type StrictOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

// Unlike Omit, this errors if key doesn't exist
type User = { id: string; name: string };
type NoId = StrictOmit<User, 'id'>; // OK
// type Bad = StrictOmit<User, 'foo'>; // Error!