TypeScript Utility Types — Partial, Pick, Omit, Record Explained | TryJS

Learn TypeScript utility types with runnable examples. Partial, Required, Pick, Omit, Record, Readonly, and more built-in mapped types.

Overview

TypeScript ships with a set of utility types that transform existing types in common ways: making every field optional, picking a subset, removing fields, creating a key-value map from a union. They're the building blocks of type-level programming in TypeScript and replace most hand-written mapped types. Knowing the main six — Partial, Required, Pick, Omit, Record, Readonly — covers 90% of real-world use cases.

How It Works

Partial<T> — all fields optional

Makes every property of T optional. Perfect for update-style functions: function update(user: User, changes: Partial<User>).

Pick<T, K> and Omit<T, K>

Pick selects a subset of keys; Omit removes them. They're complementary: Pick<User, 'id' | 'name'> gives you just those two fields, Omit<User, 'password'> gives everything except password.

Record<K, V> — key-value map

Record<'admin' | 'user', number> creates { admin: number; user: number }. The first parameter is the set of keys, the second is the value type.

Readonly<T> and ReturnType<F>

Readonly marks every property as read-only at the type level. ReturnType<typeof fn> extracts the return type of a function type — handy for inferring types from existing code.

Common Mistakes

When to Use It

Reach for these whenever you're deriving one type from another — update payloads (Partial), preview types (Pick), stripping secrets (Omit), lookup maps (Record), immutable snapshots (Readonly). They keep types in sync when the source type changes.

Runnable Example

interface User {
  id: number;
  name: string;
  email: string;
  role: "admin" | "user";
}

// Partial: all fields optional — good for update payloads
type UpdateData = Partial<User>;
const change: UpdateData = { name: "Alice" };
console.log(change);

// Pick: select specific fields
type UserPreview = Pick<User, "id" | "name">;
const preview: UserPreview = { id: 1, name: "Alice" };
console.log(preview);

// Omit: exclude specific fields
type PublicUser = Omit<User, "email">;
const pub: PublicUser = { id: 2, name: "Bob", role: "user" };
console.log(pub);

// Record: map keys to values
type RoleCount = Record<User["role"], number>;
const counts: RoleCount = { admin: 3, user: 42 };
console.log(counts);

// Readonly: immutable snapshot (shallow)
type Frozen = Readonly<User>;
const user: Frozen = { id: 3, name: "Carol", email: "c@x.io", role: "admin" };
// user.name = "Dana"; // compile error

Open this example in the TryJS playground to edit and run the code instantly in your browser — no signup needed.

Frequently Asked Questions

What is Partial<T> in TypeScript?

Partial<T> is a utility type that makes every property of T optional. It's perfect for update functions and patch payloads where the caller may supply any subset of the fields.

What is the difference between Pick and Omit?

They're complementary. Pick<T, K> creates a type with only the listed keys. Omit<T, K> creates a type with the listed keys removed. Use whichever is shorter: Pick when you want a few keys, Omit when you want most of them.

What is Record<K, V>?

Record<K, V> is a type with keys of type K and values of type V. Record<'admin' | 'user', number> is shorthand for { admin: number; user: number }. It's the canonical way to build lookup maps.

Is Readonly deep or shallow?

Shallow — only the top-level properties are marked read-only. Nested objects can still be mutated. For deep immutability you need a recursive helper type like DeepReadonly<T>.