TypeScript theorytheory 0/50 · 0%
Control flow · medium

30. Custom type guards (is)

Writing your own narrowing functions.

A type predicate (`param is Type`) lets you write a reusable function that TypeScript treats as a narrowing check, just like built-in `typeof`/`instanceof` guards.

ts
interface Erc20 { symbol: string; decimals: number; }
interface Erc721 { symbol: string; tokenId: string; }

function isErc20(t: Erc20 | Erc721): t is Erc20 {
  return "decimals" in t;
}

function describe(t: Erc20 | Erc721): string {
  if (isErc20(t)) {
    return `${t.symbol} has ${t.decimals} decimals`; // t: Erc20
  }
  return `${t.symbol} token ${t.tokenId}`; // t: Erc721
}

Custom guards are essential when the narrowing logic is more complex than a single `typeof`/`in` check — e.g. validating an unknown JSON payload against an expected shape before treating it as trusted data.

Check your understanding

  1. 1. What does `function isErc20(t: Erc20 | Erc721): t is Erc20` declare?

  2. 2. After `if (isErc20(t)) { ... }`, what is the narrowed type of `t` inside the block?

  3. 3. When are custom type guards especially useful?