Topics in this subject
TypeScript 2 min read Updated 11 Aug 2026

Type Guards and Narrowing

How to narrow down broader types (like unions) into specific types safely.

🧑‍🏫 Sabse pehle — simple mein samjho#

Jab TS mein koi variable ka type "Union" (jaise string | number) ya unknown hota hai, to TS tumhein limit kar deta hai. Tum easily unke methods use nahi kar sakte. Tumhe code ke zariye pehle "Check" karke TS ko guarantee deni hoti hai, aur tab TS ka compiler dimaag use us specific type mein Narrow (Chhota) kar deta hai. Is process ko Type Guarding / Narrowing bolte hain.

Basic Type Guards (Built-in)#

1. typeof Guard (For Primitives)#

The typeof operator is perfect for checking primitive types like string, number, boolean, and function.

function printLength(item: string | number) {
  // console.log(item.length); // ❌ ERROR: numbers do not have a length property

  if (typeof item === "string") {
    // Inside this if-block, TS knows that 'item' is definitely a string!
    console.log(item.length); // ✅ OK
  } else {
    // In this else-block, TS smartly deduces that 'item' must be a 'number'!
    console.log(item.toFixed(2)); // ✅ OK
  }
}

2. instanceof Guard (For Classes/Objects)#

If you need to verify if something is an instance of a Class, an Array, or a Date object, use instanceof.

function handleValue(dateOrString: Date | string) {
  if (dateOrString instanceof Date) {
    console.log(dateOrString.toISOString()); // ✅ Date object
  } else {
    console.log(dateOrString.toUpperCase()); // ✅ string
  }
}

3. in Operator Guard (For Object properties)#

Used to check if a specific property exists within an object ("Does this object contain this field?").

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

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    // If the swim function exists, it confirms this is a Fish
    animal.swim();
  } else {
    animal.fly(); // Otherwise, it must be a Bird
  }
}

User-Defined Type Guards (Custom Checks)#

Sometimes the built-in guards aren't enough, and you want to write a custom function to narrow down the type. This is where the special keyword is comes in.

If a custom type guard function returns true, TS understands that the variable matches the specified type.

// Type Guard Function! Pay attention to the return type: `pet is Fish`
// It translates to: "If I return true, treat 'pet' as a Fish".
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

function handlePet(pet: Fish | Bird) {
  if (isFish(pet)) {
    // As soon as this block is entered, TS narrows 'pet' down to Fish!
    pet.swim();
  } else {
    pet.fly();
  }
}

This pattern is extremely useful when filtering arrays (e.g., removing undefined values with .filter() while simultaneously narrowing the TypeScript type).