GGistDev

Utility Types in TypeScript

Leverage built-in and custom utilities to transform types.

Built-in utilities

interface User { id: number; name: string; email?: string }

type UserPartial = Partial<User>;          // all optional
type UserRequired = Required<User>;        // all required
type UserReadonly = Readonly<User>;        // all readonly

type UserIdName = Pick<User, "id" | "name">; // subset
type UserSansEmail = Omit<User, "email">;     // omit

type Dict = Record<string, number>;       // map-like

function toString(x: number) { return String(x) }
type ToStringReturn = ReturnType<typeof toString>; // string

class C { constructor(public id: number) {} }
type CInstance = InstanceType<typeof C>;  // C

type NotNull = NonNullable<string | null | undefined>; // string

Readonly and immutability helpers

type DeepReadonly<T> = { readonly [K in keyof T]: DeepReadonly<T[K]> };

Keys and values helpers

type ValueOf<T> = T[keyof T];
const COLORS = { red: "#f00", blue: "#00f" } as const;
type ColorName = keyof typeof COLORS;        // "red" | "blue"
type ColorHex = ValueOf<typeof COLORS>;      // "#f00" | "#00f"

Brand types (nominal-ish)

type Brand<T, B extends string> = T & { readonly __brand: B };
type UserId = Brand<number, "UserId">;

Brands prevent mixing values of the same structure that are conceptually different.

Optional/nullable helpers

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

Summary

  • Built-ins cover most transformations; compose them for complex shapes
  • Create small custom utilities (DeepReadonly, ValueOf, Brand) when needed