Going DeeperExtra· 45 min read

Built-in Utility Types: Partial, Pick, Omit, Record & friends

TypeScript ships ready-made type helpers that reshape an existing type for you — so you never rewrite a shape just to tweak it.

What you will learn

  • Use Partial, Required, Readonly to flip optionality and mutability
  • Reshape types with Pick, Omit and Record
  • Pull types out of functions with ReturnType, Parameters and Awaited

Why reshape a type you already have?

Imagine you have a User interface. You constantly need slightly different versions of it: a version where every field is optional (for an update form), a version with only a couple of fields (for a list), or a version with one field removed (to hide a password). Rewriting the whole shape each time is tedious and drifts out of sync.

Utility types are built-in generic helpers that take a type in and hand a reshaped type back. You already know generics — these are just generics the TypeScript team wrote for you. They are the single most-used everyday tool in real codebases, so let us meet the important ones.

Partial<T> — make every property optional

A classic case: an "update" function that changes only *some* fields of a user. Partial<User> takes User and returns a copy where every property is optional.

Partial<User> lets the caller pass any subset of fields
interface User {
  id: number;
  name: string;
  email: string;
}

function updateUser(id: number, changes: Partial<User>): void {
  console.log('Updating user ' + id + ' with', changes);
}

updateUser(1, { name: 'Asha' });            // ok — only one field
updateUser(1, { email: 'a@x.com', name: 'A' }); // ok — two fields

Note: Output: Updating user 1 with { name: 'Asha' } Updating user 1 with { email: 'a@x.com', name: 'A' } Partial<User> is the same as { id?: number; name?: string; email?: string } — every field optional. So the caller may pass just the fields they want to change.

Required<T> and Readonly<T> — the other two flippers

Required<T> does the opposite of Partial: it makes every property mandatory. Readonly<T> makes every property read-only (set once, never reassigned).

Required adds mandatory; Readonly locks against change
interface Settings {
  theme?: string;       // optional in the original
  fontSize?: number;
}

// Required: now BOTH are mandatory
const full: Required<Settings> = { theme: 'dark', fontSize: 14 };

// Readonly: the object is frozen at the type level
const locked: Readonly<Settings> = { theme: 'light' };
locked.theme = 'dark';    // error — read-only

Note: Output: Error: Cannot assign to 'theme' because it is a read-only property. Required<Settings> forces every field to be present, so leaving out fontSize would error. Readonly<Settings> keeps the fields but blocks any later reassignment.

Pick<T, Keys> and Omit<T, Keys> — choose or drop fields

Often you want a smaller slice of a big type. Pick keeps only the named fields; Omit keeps everything *except* the named fields. The field names are written as a literal union in quotes.

Pick keeps chosen fields; Omit removes chosen fields
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

// Pick: a tiny "preview" with just two fields
type UserPreview = Pick<User, 'id' | 'name'>;
const p: UserPreview = { id: 1, name: 'Asha' };

// Omit: a "safe" user with password removed
type SafeUser = Omit<User, 'password'>;
const s: SafeUser = { id: 1, name: 'Asha', email: 'a@x.com' };

console.log(p.name, s.email);

Note: Output: Asha a@x.com Pick<User, 'id' | 'name'> produces { id: number; name: string }. Omit<User, 'password'> produces the same shape as User but with password stripped out — perfect for data you send to the browser.

Record<Keys, Value> — build a lookup object type

Record<Keys, Value> describes an object whose keys come from a set and whose values all share one type. Great for dictionaries and lookup tables.

Record<Role, number> forces a value for every role
type Role = 'admin' | 'editor' | 'viewer';

// An object that maps every Role to a number (its permission level)
const levels: Record<Role, number> = {
  admin: 3,
  editor: 2,
  viewer: 1
};

console.log(levels.editor);

Note: Output: 2 Record<Role, number> means "an object with a key for each Role, each holding a number". If you forgot viewer, TypeScript would complain that a key is missing — so your lookup table can never be incomplete.

Pulling types out of functions: ReturnType, Parameters, Awaited

Some utilities read a type *out of* a function or promise, so you never hand-copy it:

  • ReturnType<typeof fn> — the type a function returns.
  • Parameters<typeof fn> — a tuple of a function’s parameter types.
  • NonNullable<T>T with null and undefined removed.
  • Awaited<T> — the value inside a Promise (what await would give you).
ReturnType reads a function’s output type; Awaited unwraps a Promise
function makeUser(name: string, age: number) {
  return { name, age, active: true };
}

// Grab the return shape automatically — no hand-typing
type NewUser = ReturnType<typeof makeUser>;
// NewUser is { name: string; age: number; active: boolean }

const u: NewUser = { name: 'Asha', age: 28, active: true };
console.log(u.active);

// Awaited unwraps a Promise's value type
type Data = Awaited<Promise<number>>;   // Data is number

Note: Output: true ReturnType<typeof makeUser> extracted { name: string; age: number; active: boolean } straight from the function — so if makeUser ever changes, NewUser updates by itself. Awaited<Promise<number>> resolves to number.

The utility-type cheat sheet

UtilityWhat it gives you
Partial<T>All properties optional
Required<T>All properties mandatory
Readonly<T>All properties read-only
Pick<T, K>Only the chosen properties
Omit<T, K>Everything except the chosen properties
Record<K, V>Object with keys K, all values V
ReturnType<F>A function’s return type
Parameters<F>A function’s parameter types as a tuple
NonNullable<T>T without null or undefined
Awaited<T>The value inside a Promise

Tip: Reach for a utility type before you copy-paste a shape. Partial for update functions, Omit to hide sensitive fields, Pick for previews, and Record for lookup tables are the four you will use almost daily.

Watch out: Utility types only *reshape* types — they create no runtime code. Omit<User, 'password'> does not delete the password from a real object at runtime; it only changes what TypeScript will *accept*. To actually strip a field from data you still write normal JavaScript.

Q. You want an update function that accepts any subset of a User’s fields. Which utility type fits?

Answer: Partial<User> makes every property optional, so the caller can pass just the fields they want to change — exactly what an update function needs.

✍️ Practice

  1. Define a Book interface, then create Pick<Book, 'title' | 'author'> and Omit<Book, 'isbn'> types with matching objects.
  2. Write a Record<'mon' | 'tue' | 'wed', number> that maps three days to a step count.

🏠 Homework

  1. Take a Product interface (id, name, price, secretCost). Create a PublicProduct with Omit (no secretCost) and an UpdateProduct with Partial. Write a one-line note on when you would use each.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →