LearnFrenzy
Sign in Take a free test

Utility and Advanced Types · Lesson 15 of 17

TypeScript Utility Types

5 min read Updated Nov 8, 2026 Saurabh Samir

TypeScript ships a set of generic utility types that transform one type into another. Instead of writing a second UserUpdate interface by hand and keeping it in sync, you write Partial<User>. Teams use them constantly for API payloads, form state and component props, so knowing them well removes a lot of duplicated types.

In this lesson

  • Shaping objects: Partial, Required, Readonly, Pick, Omit, Record
  • Filtering unions: Exclude, Extract, NonNullable
  • Reading functions: ReturnType, Parameters, Awaited
  • Combining them for real API types

Partial, Required and Readonly

interface User {
  id: number;
  name: string;
  email: string;
  phone?: string;
}

function updateUser(user: Readonly<User>, changes: Partial<User>): User {   // every field optional
  return { ...user, ...changes };
}

const asha: Readonly<User> = { id: 1, name: "Asha", email: "asha@example.com" };
const updated = updateUser(asha, { phone: "98xxxxxx10" });
console.log(updated);

const complete: Required<User> = { ...updated, phone: updated.phone ?? "" };   // every field required
console.log(Object.keys(complete).length);

Output

{ id: 1, name: 'Asha', email: 'asha@example.com', phone: '98xxxxxx10' }
4
interface User { id: number; name: string }
const asha: Readonly<User> = { id: 1, name: "Asha" };
asha.name = "Ravi";
const draft: Required<Partial<User>> = { id: 2 };
console.log(asha, draft);

Type errors

main.ts(3,6): error TS2540: Cannot assign to 'name' because it is a read-only property.
main.ts(4,7): error TS2741: Property 'name' is missing in type '{ id: number; }' but required in type 'Required<Partial<User>>'.

Pick, Omit and Record

interface User {
  id: number;
  name: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
}

type PublicUser = Omit<User, "passwordHash">;              // everything except
type UserPreview = Pick<User, "id" | "name">;              // only these
type CreateUserInput = Omit<User, "id" | "createdAt">;    // what the client sends

type Role = "admin" | "editor" | "viewer";
const permissions: Record<Role, string[]> = {             // a key for every role is required
  admin: ["read", "write", "delete"],
  editor: ["read", "write"],
  viewer: ["read"],
};

function toPublic(user: User): PublicUser {
  const { passwordHash, ...rest } = user;     // strip the secret before sending
  return rest;
}

const input: CreateUserInput = { name: "Ravi", email: "ravi@example.com", passwordHash: "x9f..." };
const saved: User = { id: 7, createdAt: new Date("2026-01-15"), ...input };
const preview: UserPreview = { id: saved.id, name: saved.name };
console.log(Object.keys(toPublic(saved)), preview, permissions.editor);

Output

[ 'id', 'createdAt', 'name', 'email' ] { id: 7, name: 'Ravi' } [ 'read', 'write' ]

Derive, don't duplicate

Keep one source type (User) and derive the rest. When a field is added to User, PublicUser and CreateUserInput pick it up automatically, and Record<Role, …> fails to compile until the new role gets an entry.

Filtering unions

type Status = "draft" | "review" | "published" | "archived";

type Live = Extract<Status, "published" | "review">;       // keep matching members
type Editable = Exclude<Status, "published" | "archived">; // remove members
type MaybeName = string | null | undefined;
type Name = NonNullable<MaybeName>;                         // string

const live: Live[] = ["review", "published"];
const editable: Editable[] = ["draft", "review"];
const name: Name = "Asha";
console.log(live, editable, name);

Output

[ 'review', 'published' ] [ 'draft', 'review' ] Asha

ReturnType, Parameters and Awaited

function createOrder(customerId: number, items: { sku: string; qty: number }[], coupon?: string) {
  return {
    id: `ORD-${customerId}-${items.length}`,
    total: items.reduce((sum, i) => sum + i.qty * 100, 0),
    coupon: coupon ?? null,
  };
}

type Order = ReturnType<typeof createOrder>;              // the inferred object type
type OrderArgs = Parameters<typeof createOrder>;          // [number, {...}[], string?]

async function fetchOrder(id: string): Promise<Order> {
  return { id, total: 250, coupon: null };
}
type FetchedOrder = Awaited<ReturnType<typeof fetchOrder>>;   // unwraps the Promise → Order

const args: OrderArgs = [42, [{ sku: "PEN", qty: 3 }], "SAVE10"];
const order: Order = createOrder(...args);
const fetched: FetchedOrder = await fetchOrder("ORD-1");
console.log(order, fetched.total);

Output

{ id: 'ORD-42-1', total: 300, coupon: 'SAVE10' } 250

These are handy when a library exports a function but not its types: ReturnType<typeof someFn> gives you the type without copying it.

UtilityResult
Partial<T> / Required<T>all properties optional / required
Readonly<T>all properties read-only
Pick<T, K> / Omit<T, K>keep / drop the listed keys
Record<K, V>object with keys K and values V
Exclude<U, X> / Extract<U, X>remove / keep union members
NonNullable<T>remove null and undefined
ReturnType<F> / Parameters<F>a function's return type / argument tuple
Awaited<T>the value inside a Promise

Practice

Try it yourself

  1. Define ProductForm: every field of Product except id, all optional, for a half-filled form.

    Show solution
    interface Product { id: number; name: string; price: number; tags: string[] }
    type ProductForm = Partial<Omit<Product, "id">>;
    
    const draft: ProductForm = { name: "Notebook" };
    const ready: ProductForm = { name: "Notebook", price: 120, tags: ["stationery"] };
    console.log(Object.keys(draft).length, Object.keys(ready).length);

    Output

    1 3

Quick check

Difference between Pick and Omit?

Pick keeps the listed keys; Omit keeps everything except them.

Does Readonly<T> freeze the object at run time?

No – it's compile-time only. Use Object.freeze for run-time protection.

How do you get the resolved type of an async function?

Awaited<ReturnType<typeof fn>>.

Summary

  • Utility types derive new types from one source type – no duplicated interfaces.
  • Partial/Required/Readonly/Pick/Omit/Record shape objects; Exclude/Extract/NonNullable filter unions.
  • ReturnType, Parameters and Awaited read types from functions.

Finished this lesson?

Mark it complete to track your progress, then carry on with the next lesson.

Next lesson

Search LearnFrenzy

Esc

Quick links