Type Guards & Narrowing Patterns

How narrowing works in TypeScript: typeof/in, custom type guards, assertion functions, and practical patterns for safer code.

F

Frontend Interview Team

February 08, 2026

1 min read
Type Guards & Narrowing Patterns

30‑second interview answer

TypeScript uses control-flow analysis to narrow types based on runtime checks (typeof, in, instanceof). For complex checks, write custom type guards (x is Foo) or assertion functions (asserts x is Foo). This turns unsafe unknown into safe, specific types.


Built-in narrowing

typeof

function print(x: string | number) {
  if (typeof x === 'string') {
    return x.toUpperCase();
  }
  return x.toFixed(2);
}

in

type A = { a: string };
type B = { b: number };
 
function f(x: A | B) {
  if ('a' in x) return x.a;
  return x.b;
}

instanceof

function handle(e: unknown) {
  if (e instanceof Error) {
    return e.message;
  }
  return String(e);
}

Custom type guards

type User = { id: string; name: string };
 
function isUser(x: unknown): x is User {
  return !!x && typeof x === 'object' && 'id' in x && 'name' in x;
}
 
const data: unknown = JSON.parse('{"id":"1","name":"Raj"}');
if (isUser(data)) {
  data.name.toUpperCase(); // ✅
}

Tip

Keep guards small and composable. For real validation, use Zod.


Assertion functions (asserts)

function assertIsError(e: unknown): asserts e is Error {
  if (!(e instanceof Error)) {
    throw new Error('Not an Error');
  }
}
 
function logError(e: unknown) {
  assertIsError(e);
  console.log(e.stack);
}

Common interview traps

  • Mistaking runtime validation for compile-time types.
  • Writing guards that are too weak (only checks one field).
  • Overusing type assertions (as Foo) instead of guards.

Mini Q&A

Q1: What does x is Foo mean?

  • It’s a predicate telling TS that inside the true branch, x is Foo.

Q2: When use asserts?

  • When you want to throw if the check fails and narrow afterwards.

Q3: Why prefer guards over as?

  • Guards are safer; as can lie.

Summary checklist

  • I can narrow with typeof/in/instanceof.
  • I can write a type guard.
  • I can use assertion functions.
  • I avoid unsafe as.