🇬🇧 Limited Time — UK Only·🎓 Free Learning for 1 Month·🤖 Free AI Training Included·📚 4,000+ Lessons · 35,000+ Quizzes·🏆 GCSE Mocks · Olympiad Papers·⚡ Selected Students Only · Limited Places·🎁 Free Value Worth £2,000·🇬🇧 Limited Time — UK Only·🎓 Free Learning for 1 Month·🤖 Free AI Training Included·📚 4,000+ Lessons · 35,000+ Quizzes·🏆 GCSE Mocks · Olympiad Papers·⚡ Selected Students Only · Limited Places·🎁 Free Value Worth £2,000·🇬🇧 Limited Time — UK Only·🎓 Free Learning for 1 Month·🤖 Free AI Training Included·📚 4,000+ Lessons · 35,000+ Quizzes·🏆 GCSE Mocks · Olympiad Papers·⚡ Selected Students Only · Limited Places·🎁 Free Value Worth £2,000·
📘 TypeScript

Narrowing with typeof and in

📚 What is Type Narrowing in TypeScript? Type narrowing is when TypeScript gets more specific about a type inside a conditional block. If a variable is string | number and you write if (typeof x === 'string') { ... }, TypeScript KNOWS inside that block x is a string -- so it unlocks string methods.…

8 min 10 XP Lesson 16 of 21
Narrowing with typeof and in
🌐

Appy Says…

A value typed as string | number can be either. Before you call string methods on it, you need to prove it's actually a string — that's narrowing. TypeScript tracks your checks and narrows the type inside if blocks automatically.

📖

What is Type Narrowing?

Type narrowing is TypeScript's ability to deduce a more specific type within a code block based on a conditional check. After a guard, the type is narrowed inside the branch.

  • typeof guard: if (typeof x === 'string') { x.toUpperCase(); }
  • instanceof guard: if (x instanceof Date) { x.toISOString(); }
  • Truthiness: if (user) { user.name; } — narrows out null/undefined
  • Equality: if (x === null) { ... } else { // x is not null }
  • in operator: if ('name' in obj) { obj.name; }
  • Discriminated union: if (shape.kind === 'circle') { shape.radius; }
🎮

Think of it like verifying a Minecraft item before using it

Before crafting, you check what's in the slot: 'if this is a sword, sharpen it; if it's a pickaxe, use it to mine'. TypeScript does the same: your runtime check teaches TypeScript what type it is so it can let you call the right methods.

⚙️

How It Works

  • 1. Function receives value: string | number | null
  • 2. if (typeof value === 'string') { ... } — inside: value is string
  • 3. else if (typeof value === 'number') { ... } — inside: value is number
  • 4. else { ... } — inside: value is null (all other cases exhausted)
  • 5. TypeScript's control flow analysis tracks narrowing through if/else/switch/early return
  • 6. Type guard function: function isUser(x: any): x is User { return 'name' in x; }
🌍

Real-World Examples

  • if (typeof id === 'string') { id.trim() } else { id.toFixed(0) }
  • if (err instanceof Error) { console.error(err.message) }
  • if (response.ok) { const data = await response.json() } // TypeScript narrows here
  • Discriminated union: switch (action.type) { case 'ADD': action.payload; }
💡

Key Facts

  • TypeScript's narrowing is flow-based — it follows every branch and knows the type at each point
  • Early return is the cleanest narrowing pattern: if (!user) return; user.name; // safe
  • User-defined type guards: x is User return type lets you teach TypeScript about custom runtime checks
  • TypeScript 4.4 improved narrowing of aliased conditions — const isString = typeof x === 'string'; if (isString) { ... }
⚠️

Watch Out!

Don't use typeof null === 'object' to check for null — it returns 'object' (a JavaScript legacy bug). Always check === null explicitly. For an object that might be null: if (x !== null && typeof x === 'object').

📌

Remember

typeof, instanceof, truthiness, and discriminated union checks all narrow types in TypeScript. After the check, TypeScript knows the specific type inside the branch — you get full intellisense for that narrowed type.

What You Learned

  • Narrowing: TypeScript tracks type guards and deduces specific types inside if/switch branches
  • typeof, instanceof, truthiness, discriminated unions — all narrow the type automatically
  • Unlocks: safe handling of union types, exhaustive switch statements, working with unknown API data

Key Facts

  • TypeScript's narrowing is flow-based — it follows every branch and knows the type at each point
  • Early return is the cleanest narrowing pattern: if (!user) return; user.name; // safe
  • User-defined type guards: x is User return type lets you teach TypeScript about custom runtime checks
  • TypeScript 4.4 improved narrowing of aliased conditions — const isString = typeof x === 'string'; if (isString) { ... }

Real-World Examples

• <code>if (typeof id === 'string') { id.trim() } else { id.toFixed(0) }</code> • <code>if (err instanceof Error) { console.error(err.message) }</code> • <code>if (response.ok) { const data = await response.json() } // TypeScript narrows here</code> • Discriminated union: <code>switch (action.type) { case 'ADD': action.payload; }</code>

Remember

typeof, instanceof, truthiness, and discriminated union checks all narrow types in TypeScript. After the check, TypeScript knows the specific type inside the branch — you get full intellisense for that narrowed type.

Quick Quiz

1 / 2

typeof x === 'string' narrows?

    Narrowing with typeof and in — Applaa Academy