Advanced Lesson Β· 12

Utility
Types

TypeScript ships with powerful built-in type helpers that transform existing types into new ones β€” without writing them from scratch.

πŸ—ΊοΈ Overview

Utility types are generic types built into TypeScript that let you construct new types based on existing ones. Instead of duplicating type definitions, you compose them.

Utility TypeWhat it does
Partial<T>Makes all properties optional
Required<T>Makes all properties required
Readonly<T>Makes all properties read-only
Pick<T, K>Picks only specified keys from T
Omit<T, K>Removes specified keys from T
Record<K, V>Creates an object type with keys K and values V
Exclude<T, U>Removes types in U from union T
Extract<T, U>Keeps only types in T that match U
NonNullable<T>Removes null and undefined from T
ReturnType<T>Gets the return type of a function

πŸ”§ Partial<T>

Makes all properties optional. Perfect for update functions where you only want to pass the fields you're changing.

partial.ts
interface User {
  name: string;
  age: number;
  email: string;
  role: string;
}

// Without Partial β€” you'd need all fields every time
function updateUser(id: number, data: Partial<User>): void {
  // data can have any subset of User fields
}

updateUser(1, { name: "Alice" });          // βœ… just name
updateUser(2, { email: "[email protected]" }); // βœ… just email
updateUser(3, { age: 30, role: "admin" }); // βœ… two fields

// Partial<User> is equivalent to:
type PartialUser = {
  name?: string;
  age?: number;
  email?: string;
  role?: string;
};

βœ… Required<T>

The opposite of Partial β€” makes every property required, even optional ones.

required.ts
interface Config {
  host?: string;
  port?: number;
  debug?: boolean;
}

// Before saving to DB, ensure everything is set
function saveConfig(cfg: Required<Config>): void {
  console.log(cfg.host);  // guaranteed to exist
  console.log(cfg.port);  // guaranteed to exist
}

// saveConfig({ host: "localhost" }); ❌ port and debug missing
saveConfig({ host: "localhost", port: 3000, debug: false }); // βœ…

βœ‚οΈ Pick<T, K> & Omit<T, K>

Pick creates a type with only the keys you want. Omit creates a type with specific keys removed. They're inverses of each other.

pick-omit.ts
interface User {
  id: number;
  name: string;
  email: string;
  password: string;  // sensitive!
  createdAt: Date;
}

// Pick only what the UI needs to show
type UserCard = Pick<User, "id" | "name" | "email">;
// { id: number; name: string; email: string }

// Omit sensitive fields before sending to client
type PublicUser = Omit<User, "password">;
// { id, name, email, createdAt } β€” password removed!

function getPublicProfile(user: User): PublicUser {
  const { password, ...rest } = user;
  return rest;
}

πŸ’‘ Rule of thumb: Use Pick when you want a few keys from a large type. Use Omit when you want all keys except a few.

πŸ—‚οΈ Record<K, V>

Creates an object type where all keys are type K and all values are type V. Great for maps, dictionaries, and lookups.

record.ts
// Map string keys to numbers
const scores: Record<string, number> = {
  alice: 95,
  bob: 87,
  charlie: 91,
};

// Enforce specific keys with a union type
type Fruit = "apple" | "banana" | "orange";

const inventory: Record<Fruit, number> = {
  apple: 50,
  banana: 30,
  orange: 20,
  // "grape": 10  ❌ not in Fruit union
};

// Record with object values
interface PageInfo { title: string; url: string; }

type Pages = Record<string, PageInfo>;

const routes: Pages = {
  home:  { title: "Home",  url: "/" },
  about: { title: "About", url: "/about" },
};
rk on union types to filter or narrow down the allowed values.

exclude-extract.ts
type Animal = "cat" | "dog" | "fish" | "bird";

// Remove "fish" from the union
type LandAnimal = Exclude<Animal, "fish">;
// "cat" | "dog" | "bird"

// Keep only pets that can cuddle
type CuddlyPet = Extract<Animal, "cat" | "dog">;
// "cat" | "dog"

// Remove null and undefined
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// string

// ReturnType extracts what a function returns
function getUser() { return { name: "Alice", age: 25 }; }
type UserData = ReturnType<typeof getUser>;
// { name: string; age: number }

⚑ Combining Utility Types

The real power comes from composing multiple utility types together:

combining.ts
interface Article {
  id: number;
  title: string;
  body: string;
  author: string;
  publishedAt: Date;
  tags: string[];
}

// Only the fields needed for article creation (no id/publishedAt yet)
type CreateArticle = Omit<Article, "id" | "publishedAt">;

// Patch endpoint β€” any subset of CreateArticle fields
type UpdateArticle = Partial<CreateArticle>;

// Preview card β€” just title, author, tags
type ArticlePreview = Readonly<Pick<Article, "title" | "author" | "tags">>;
←
Previous
Lesson 11 β€” Modules
You are here
12 / 17
Next Lesson
Lesson 13 β€” Decorators
β†’