Type Narrowing & Guards

Type Narrowing is the process of refining a broad type (like string | number) down to a more specific type within conditional code blocks.

1. `typeof` Type Guards

function printLength(input: string | number) {
  if (typeof input === "string") {
    // TypeScript knows input is string here!
    console.log(input.toUpperCase(), input.length);
  } else {
    // TypeScript knows input is number here!
    console.log(input.toFixed(2));
  }
}

2. `instanceof` & `in` Operator Guards

// 1. instanceof Guard (For Classes & Objects)
function handleDate(val: Date | string) {
  if (val instanceof Date) {
    console.log(val.getFullYear()); // Safe Date method
  }
}

// 2. 'in' Operator Guard (Property Check)
interface Admin { permissions: string[] }
interface User { username: string }

function handleAccount(account: Admin | User) {
  if ("permissions" in account) {
    console.log("Admin permissions:", account.permissions);
  }
}

3. Custom Type Predicates (`is` Keyword)

Write custom boolean helper functions that narrow types using the param is Type signature:

interface Fish { swim: () => void }
interface Bird { fly: () => void }

// Custom Type Guard Function
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

function moveAnimal(pet: Fish | Bird) {
  if (isFish(pet)) {
    pet.swim(); // TypeScript knows pet is Fish!
  } else {
    pet.fly();  // TypeScript knows pet is Bird!
  }
}

Next Up

Master Classes & OOP in TypeScript: access modifiers, parameter properties, and abstract classes.

Next Lesson: Classes & OOP →