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