telos
Aula
DA
Product engineering with TypeScriptModule 03 · Design patterns in TSLesson 03.5

Discriminated unions in practice

18:24 · with Carolina Rabech

Progress
type Result<T, E = HttpError> =
  | { kind: 'ok'; value: T }
  | { kind: 'err'; error: E }
  | { kind: 'pending' };

function render(r: Result<User>) {
  switch (r.kind) {
    case 'pending': return <Skeleton />;
    case 'err': return <Banner error={r.error} />;
    case 'ok': return <Profile user={r.value} />;
  }
}
Lesson 03.5
07:42 / 18:24
Carolina Rabech
Carolina Rabech
Senior engineer · ex-Stone and Loft
4.92·8.412 students
About this lesson

Discriminated unions are the cheapest way to get rid of nested `if-else` and let the compiler carry the context for you. In this lesson we refactor an HTTP client that mixes success, error and an in-between state into a single response — and watch the linter turn into a PR reviewer.

result.ts · refactor
type Result<T, E = HttpError> =
  | { kind: 'ok'; value: T }
  | { kind: 'err'; error: E }
  | { kind: 'pending' };

function render(r: Result<User>) {
  switch (r.kind) {
    case 'pending': return <Skeleton />;
    case 'err': return <Banner error={r.error} />;
    case 'ok': return <Profile user={r.value} />;
  }
}
What this lesson covers
  • How the kind discriminator cuts nested if out of every consumer.
  • Why never in the switch default is your best friend during a refactor.
  • Real costs: when this pattern starts to hurt, and how to work around it.
  • A side-by-side comparison with try/catch and exception-based code.