Utility types cheatsheet.

Partial / Required

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

type PatchUser = Partial<User>;          // all optional
type FullUser = Required<User>;          // all required (email becomes string)

Readonly

type RoUser = Readonly<User>;
// { readonly id: number; readonly name: string; ... }

Shallow — for deep, write your own:

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

Pick / Omit

type Public = Pick<User, "id" | "name">;
type NoEmail = Omit<User, "email">;

Pick includes keys; Omit excludes.

Record

type RoleMap = Record<"admin" | "user", boolean>;
// { admin: boolean; user: boolean }

type ById<T> = Record<string, T>;

Exclude / Extract

type Animal = "dog" | "cat" | "fish";
type Land = Exclude<Animal, "fish">;     // "dog" | "cat"
type Aqua = Extract<Animal, "fish">;     // "fish"

NonNullable

type T = string | number | null | undefined;
type Solid = NonNullable<T>;             // string | number

ReturnType / Parameters

function f(a: string, b: number): boolean { return true; }

type R = ReturnType<typeof f>;       // boolean
type P = Parameters<typeof f>;       // [string, number]

const args: P = ["hi", 42];
f(...args);

ConstructorParameters / InstanceType

class C {
  constructor(public name: string) {}
}

type Args = ConstructorParameters<typeof C>;     // [string]
type Inst = InstanceType<typeof C>;              // C

Awaited

type R = Awaited<Promise<Promise<string>>>;      // string

Unwraps all nesting.

ThisParameterType / OmitThisParameter

function f(this: { x: number }, y: number) {}

type T = ThisParameterType<typeof f>;            // { x: number }
type Bound = OmitThisParameter<typeof f>;        // (y: number) => void

String manipulation types

type Up = Uppercase<"hello">;            // "HELLO"
type Lo = Lowercase<"HELLO">;            // "hello"
type Cap = Capitalize<"hello">;          // "Hello"
type Un = Uncapitalize<"HELLO">;         // "hELLO"

Template literal types

type Event = "click" | "hover";
type Handler = `on${Capitalize<Event>}`;   // "onClick" | "onHover"

type Path = `/users/${number}`;
const p: Path = `/users/${42}`;

Useful combinations

Partial + required keys

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

type X = PartialBy<User, "email">;     // email optional, others required

Required + optional keys

type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;

Pick by value type

type PickByValue<T, V> = {
  [K in keyof T as T[K] extends V ? K : never]: T[K]
};

type StringFields = PickByValue<User, string>;   // { name: string }

Deep partial

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

Mutable (strip readonly)

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

Required keys only

type RequiredKeys<T> = {
  [K in keyof T]-?: {} extends Pick<T, K> ? never : K
}[keyof T];

Symmetric difference

type Diff<A, B> = Exclude<A, B> | Exclude<B, A>;

Common mistakes

  • Omit<T, K> doesn’t enforce K is a real key (for unions). Use Omit<T, K & keyof T> if you want strictness.
  • Partial is shallow. Nested objects retain required keys.
  • Record<string, T> includes prototype keys — use noUncheckedIndexedAccess so access returns T | undefined.
  • Mixing Pick and Omit — pick the one that’s shorter to read.
  • Required doesn’t recurse — make a DeepRequired if needed.

Read this next

If you want my utility-types extension library, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .