0Pricing
TypeScript Academy · Lesson

Refining unions across function boundaries

Carry safe narrowing across function boundaries using discriminated unions, predicate returns, and Result-style types.

Intro

Goal: Keep your narrowing intact across function calls using tagged unions, predicate returns, and validation helpers.

  • Zero unsafe as at call sites
  • Refinements travel with data

Tagged union return

Result pattern: caller narrows by checking ok. No casts, clear control flow.

type Ok<T> = { ok: true; value: T }
type Err = { ok: false; error: string }

type Result<T> = Ok<T> | Err

function parseIntSafe(s: string): Result<number> {
  const n = Number(s)
  return Number.isFinite(n) ? { ok: true, value: n } : { ok: false, error: "NaN" }
}

function useIt(s: string) {
  const r = parseIntSafe(s)
  if (r.ok) {
    // r is Ok<number>
    return r.value * 2
  }
  // r is Err
  return `bad: ${r.error}`
}

All lessons in this course

  1. Exhaustive switches & never checks
  2. Predicate functions & satisfies operator
  3. Refining unions across function boundaries
← Back to TypeScript Academy