← Back to Course

🛠️ Utility Types

TypeScript includes powerful built-in utility types that transform existing types in useful ways. These utilities help you avoid repetition and create flexible type definitions.

Partial<T>

Makes all properties optional. Perfect for update functions:

Example: Partial

interface Player {
  name: string;
  health: number;
  level: number;
  experience: number;
}

// Update only some properties
function updatePlayer(
  player: Player,
  updates: Partial<Player>
): Player {
  return { ...player, ...updates };
}

const hero: Player = {
  name: "Hero",
  health: 100,
  level: 5,
  experience: 1200
};

// Update only health and experience
const updated = updatePlayer(hero, {
  health: 80,
  experience: 1350
});

Required<T>

Makes all properties required (opposite of Partial):

Example: Required

interface GameConfig {
  difficulty?: string;
  sound?: boolean;
  graphics?: string;
}

// Function requires all config options
function initializeGame(config: Required<GameConfig>): void {
  console.log(`Difficulty: ${config.difficulty}`);
  console.log(`Sound: ${config.sound}`);
  console.log(`Graphics: ${config.graphics}`);
}

initializeGame({
  difficulty: "normal",
  sound: true,
  graphics: "high"
});  // All required!

// initializeGame({ difficulty: "easy" });  // ✗ Error - missing properties

Readonly<T>

Makes all properties readonly (immutable):

Example: Readonly

interface Point {
  x: number;
  y: number;
}

const mutablePoint: Point = { x: 10, y: 20 };
mutablePoint.x = 15;  // ✓ OK

const immutable Point: Readonly<Point> = { x: 10, y: 20 };
// immutablePoint.x = 15;  // ✗ Error - readonly property

// Useful for function parameters
function calculateDistance(
  p1: Readonly<Point>,
  p2: Readonly<Point>
): number {
  const dx = p2.x - p1.x;
  const dy = p2.y - p1.y;
  return Math.sqrt(dx * dx + dy * dy);
}

Pick<T, K>

Creates a type by picking specific properties from another type:

Example: Pick

interface User {
  id: number;
  username: string;
  email: string;
  password: string;
  createdAt: Date;
  updatedAt: Date;
}

// Pick only public-facing properties
type PublicUser = Pick<User, "id" | "username" | "createdAt">;

// Equivalent to:
// type PublicUser = {
//   id: number;
//   username: string;
//   createdAt: Date;
// }

function displayUser(user: PublicUser): void {
  console.log(`${user.username} (ID: ${user.id})`);
  // Cannot access user.email or user.password (not in type)
}

Omit<T, K>

Creates a type by omitting specific properties (opposite of Pick):

Example: Omit

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
  stock: number;
  internalNotes: string;
}

// Omit sensitive internal properties
type PublicProduct = Omit<Product, "internalNotes" | "stock">;

// Equivalent to:
// type PublicProduct = {
//   id: number;
//   name: string;
//   price: number;
//   description: string;
// }

function displayProduct(product: PublicProduct): void {
  console.log(`${product.name}: $${product.price}`);
}

// Useful for creating types without certain properties
type UserWithoutPassword = Omit<User, "password">;

Record<K, T>

Creates an object type with specific keys and value types:

Example: Record

// Map string keys to numbers
type Scores = Record<string, number>;

const gameScores: Scores = {
  "player1": 1500,
  "player2": 2300,
  "player3": 1800
};

// Map specific keys to a type
type PageInfo = {
  title: string;
  description: string;
};

type SitePages = Record<"home" | "about" | "contact", PageInfo>;

const pages: SitePages = {
  home: { title: "Home", description: "Welcome page" },
  about: { title: "About", description: "About us" },
  contact: { title: "Contact", description: "Get in touch" }
};

// Useful for creating lookup objects
type HttpStatus = Record<number, string>;

const statusMessages: HttpStatus = {
  200: "OK",
  404: "Not Found",
  500: "Server Error"
};

Exclude<T, U> and Extract<T, U>

Work with union types to include or exclude members:

Example: Exclude and Extract

type AllEvents = "click" | "scroll" | "mousemove" | "keypress";

// Exclude specific members
type UIEvents = Exclude<AllEvents, "scroll" | "mousemove">;
// Result: "click" | "keypress"

// Extract specific members
type MouseEvents = Extract<AllEvents, "click" | "mousemove">;
// Result: "click" | "mousemove"

// Exclude null and undefined
type NoNullable<T> = Exclude<T, null | undefined>;

type MaybeString = string | null | undefined;
type DefiniteString = NoNullable<MaybeString>;  // string

ReturnType<T> and Parameters<T>

Extract types from function signatures:

Example: ReturnType and Parameters

// Get the return type of a function
function createPlayer(name: string, level: number) {
  return {
    name,
    level,
    health: 100,
    isAlive: true
  };
}

type Player = ReturnType<typeof createPlayer>;
// Player = { name: string; level: number; health: number; isAlive: boolean; }

// Get parameter types of a function
type CreatePlayerParams = Parameters<typeof createPlayer>;
// CreatePlayerParams = [name: string, level: number]

function callWithArgs(
  fn: typeof createPlayer,
  ...args: Parameters<typeof createPlayer>
) {
  return fn(...args);
}

const player = callWithArgs(createPlayer, "Hero", 5);

Combining Utility Types

Example: Advanced Combinations

interface CompleteUser {
  id: number;
  username: string;
  email: string;
  password: string;
  profile: {
    age?: number;
    bio?: string;
  };
  settings: {
    theme: string;
    notifications: boolean;
  };
}

// Partial user for updates, but ID is required
type UserUpdate = Partial<Omit<CompleteUser, "id">> & Pick<CompleteUser, "id">;

// Public user: omit password, make everything readonly
type PublicUser = Readonly<Omit<CompleteUser, "password">>;

// New user registration (no ID yet, password required)
type UserRegistration = Omit<CompleteUser, "id"> & {
  passwordConfirm: string;
};

🎯 Key Concepts

  • Partial<T> - all properties optional
  • Required<T> - all properties required
  • Readonly<T> - all properties immutable
  • Pick<T, K> - select specific properties
  • Omit<T, K> - remove specific properties
  • Record<K, T> - object type with specific keys
  • Utility types can be combined for complex transformations
← Back to Intermediate Course