Syntax Cache
BlogMethodFeaturesHow It WorksBuild a Game
  1. Home
  2. Cheat Sheets
  3. TypeScript
  4. TypeScript Utility Types Cheat Sheet
TypeScriptCheat Sheet

TypeScript Utility Types Cheat Sheet

Every built-in utility type with practical examples -- Partial, Pick, Omit, Record, ReturnType, Awaited, and string manipulation types.

On this page
  1. 1Partial, Required, Readonly
  2. 2Pick and Omit
  3. 3Record
  4. 4Extract and Exclude
  5. 5NonNullable
  6. 6ReturnType and Parameters
  7. 7Awaited
  8. 8String Manipulation Types
  9. 9Composing Utility Types
Partial, Required, ReadonlyPick and OmitRecordExtract and ExcludeNonNullableReturnType and ParametersAwaitedString Manipulation TypesComposing Utility Types

Partial, Required, Readonly

Modify property modifiers across an entire type in one step.

Partial makes all properties optional
interface User {
  id: number;
  name: string;
  email: string;
}

type UserUpdate = Partial<User>;
// => { id?: number; name?: string; email?: string }

function updateUser(id: number, changes: Partial<User>): void {
  // changes.name is string | undefined
}
updateUser(1, { name: 'Bob' });  // => OK, email not required
Required makes all properties non-optional
interface Config {
  host?: string;
  port?: number;
  debug?: boolean;
}

type ResolvedConfig = Required<Config>;
// => { host: string; port: number; debug: boolean }

function startServer(config: Required<Config>): void {
  console.log(config.host);  // => type: string (not string | undefined)
}
Readonly prevents mutation
interface Settings {
  theme: string;
  fontSize: number;
}

const defaults: Readonly<Settings> = { theme: 'dark', fontSize: 14 };
// defaults.theme = 'light';  // => Error: cannot assign to readonly property

// Readonly is shallow -- nested objects are still mutable
interface Deep { nested: { value: number } }
const obj: Readonly<Deep> = { nested: { value: 1 } };
obj.nested.value = 2;  // => OK (Readonly doesn't recurse)

For deep readonly, use a library like ts-essentials DeepReadonly or a recursive mapped type.

Pick and Omit

Select or exclude properties from an existing type to create a narrower type.

Pick keeps listed properties
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

type UserPreview = Pick<User, 'id' | 'name'>;
// => { id: number; name: string }

type LoginCredentials = Pick<User, 'email' | 'password'>;
// => { email: string; password: string }
Omit removes listed properties
type PublicUser = Omit<User, 'password'>;
// => { id: number; name: string; email: string }

type CreateUserInput = Omit<User, 'id'>;
// => { name: string; email: string; password: string }

Omit doesn't error on invalid keys: `Omit<User, 'nonexistent'>` silently returns the full type. Use a custom StrictOmit if you need compile-time safety.

Composing Pick and Omit
// Optional updates excluding id
type UserUpdate = Partial<Omit<User, 'id'>>;
// => { name?: string; email?: string; password?: string }

// Required subset
type RequiredProfile = Required<Pick<User, 'name' | 'email'>>;
// => { name: string; email: string }

Record

Create object types with specific key and value types.

String-keyed lookup table
type StatusColors = Record<string, string>;

const colors: StatusColors = {
  success: '#22c55e',
  warning: '#eab308',
  error: '#ef4444',
};
Union-keyed Record (exhaustive)
type Role = 'admin' | 'editor' | 'viewer';

const permissions: Record<Role, string[]> = {
  admin: ['read', 'write', 'delete'],
  editor: ['read', 'write'],
  viewer: ['read'],
};
// Missing a role key => compile error

Record<UnionKey, V> enforces that every union member has an entry. This is the easiest way to guarantee exhaustive mappings.

Record vs index signature
// These are equivalent for string keys:
type A = Record<string, number>;
type B = { [key: string]: number };

// Record is more flexible -- works with union keys:
type StatusMap = Record<'ok' | 'error', string>;
// => { ok: string; error: string }

Extract and Exclude

Filter union type members by assignability.

Extract keeps matching members
type Input = string | number | boolean | null;

type StringOrNumber = Extract<Input, string | number>;
// => string | number

type Falsy = Extract<Input, false | null | 0 | ''>;
// => null (only null is in both)
Exclude removes matching members
type Input = string | number | boolean | null;

type NonNull = Exclude<Input, null>;
// => string | number | boolean

type NotString = Exclude<Input, string>;
// => number | boolean | null
Filter object types from a union
type Event =
  | { type: 'click'; x: number; y: number }
  | { type: 'keypress'; key: string }
  | { type: 'scroll'; offset: number };

type ClickEvent = Extract<Event, { type: 'click' }>;
// => { type: 'click'; x: number; y: number }

type NonScrollEvent = Exclude<Event, { type: 'scroll' }>;
// => { type: 'click'; x: number; y: number } | { type: 'keypress'; key: string }

NonNullable

Strip `null` and `undefined` from a type.

Remove null and undefined
type MaybeString = string | null | undefined;

type DefiniteString = NonNullable<MaybeString>;
// => string
Use with mapped types
interface FormData {
  name: string | null;
  email: string | undefined;
  age: number | null | undefined;
}

type RequiredFormData = {
  [K in keyof FormData]: NonNullable<FormData[K]>;
};
// => { name: string; email: string; age: number }

NonNullable is shorthand for Exclude<T, null | undefined>.

ReturnType and Parameters

Extract the return type or parameter types from function types.

ReturnType extracts the return
function fetchUser(id: number) {
  return { id, name: 'Alice', active: true };
}

type User = ReturnType<typeof fetchUser>;
// => { id: number; name: string; active: boolean }

Use `typeof` to get the function type from a value. ReturnType works on types, not values.

Parameters extracts argument types
function createUser(name: string, age: number, role: 'admin' | 'user') {
  // ...
}

type CreateArgs = Parameters<typeof createUser>;
// => [name: string, age: number, role: 'admin' | 'user']

type FirstArg = CreateArgs[0];  // => string
type ThirdArg = CreateArgs[2];  // => 'admin' | 'user'
ConstructorParameters for classes
class Database {
  constructor(host: string, port: number) {}
}

type DbArgs = ConstructorParameters<typeof Database>;
// => [host: string, port: number]

Awaited

Unwrap the resolved type of a Promise (recursively).

Unwrap a Promise type
type A = Awaited<Promise<string>>;         // => string
type B = Awaited<Promise<Promise<number>>>;  // => number (recursive)
type C = Awaited<string | Promise<number>>;  // => string | number
Infer async function return types
async function loadConfig() {
  const response = await fetch('/api/config');
  return response.json() as Promise<{ apiUrl: string; debug: boolean }>;
}

type Config = Awaited<ReturnType<typeof loadConfig>>;
// => { apiUrl: string; debug: boolean }

Awaited<ReturnType<typeof fn>> is the standard pattern for getting the resolved return type of an async function.

String Manipulation Types

Built-in types that transform string literal types at the type level.

Uppercase, Lowercase, Capitalize, Uncapitalize
type A = Uppercase<'hello'>;       // => 'HELLO'
type B = Lowercase<'HELLO'>;       // => 'hello'
type C = Capitalize<'hello'>;      // => 'Hello'
type D = Uncapitalize<'Hello'>;    // => 'hello'
Transform union members
type EventName = 'click' | 'scroll' | 'keypress';

type UpperEvents = Uppercase<EventName>;
// => 'CLICK' | 'SCROLL' | 'KEYPRESS'

type HandlerName = `on${Capitalize<EventName>}`;
// => 'onClick' | 'onScroll' | 'onKeypress'

String manipulation types distribute over unions automatically.

Composing Utility Types

Combine utility types to build precisely the shape you need.

API request and response types from a base model
interface Article {
  id: string;
  title: string;
  body: string;
  authorId: string;
  createdAt: Date;
  updatedAt: Date;
}

// POST request: no id or timestamps
type CreateArticle = Omit<Article, 'id' | 'createdAt' | 'updatedAt'>;

// PATCH request: partial updates, no changing id
type UpdateArticle = Partial<Omit<Article, 'id' | 'createdAt' | 'updatedAt'>>;

// GET response: everything, readonly
type ArticleResponse = Readonly<Article>;
Make specific fields required
type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;

interface Options {
  timeout?: number;
  retries?: number;
  baseUrl?: string;
}

type ResolvedOptions = WithRequired<Options, 'baseUrl'>;
// => { timeout?: number; retries?: number; baseUrl: string }

This pattern intersects the original type with a Required subset -- a common custom utility.

Deep Partial (recursive)
type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};

interface Config {
  database: { host: string; port: number };
  cache: { ttl: number; maxSize: number };
}

type PartialConfig = DeepPartial<Config>;
// database?.host, database?.port, cache?.ttl, cache?.maxSize all optional
Learn TypeScript in Depth
Utility Types →
Warm-up1 / 1

Can you write this from memory?

Create type Scores for an object with string keys and number values

See Also
Generics →Interface vs Type →

Start Practicing TypeScript

Free daily exercises with spaced repetition. No credit card required.

← Back to TypeScript Syntax Practice
Syntax Cache

Build syntax muscle memory with spaced repetition.

Product

  • Pricing
  • Our Method
  • Daily Practice
  • Design Patterns
  • Interview Prep

Resources

  • Blog
  • Compare
  • Cheat Sheets
  • Vibe Coding
  • Muscle Memory

Languages

  • Python
  • JavaScript
  • TypeScript
  • Rust
  • SQL
  • GDScript

Legal

  • Terms
  • Privacy
  • Contact

© 2026 Syntax Cache

Cancel anytime in 2 clicks. Keep access until the end of your billing period.

No refunds for partial billing periods.