M Logo
๐Ÿ“ TypeScript from Zero ยท Part 19 of 50

TypeScript Discriminated Unions and Exhaustive switch with never

November 6, 2026

Welcome to episode 19 of TypeScript from Zero, a series for complete beginners (no JavaScript needed). Welcome back to TypeScript from zero! Today: a pattern for values that come in several kinds. We stay in the shop project, with a new file called shapes two.ts. Every code block below is the code from the video, ready to copy; run each file to see the output.

Setup

We start in the terminal and open the project in VS Code:

bash
$ touch src/shapes2.ts

1. Union

A shape is a circle, a square, or a triangle. Each kind is an object with its own properties, and all of them share one property called kind, with an exact text. That shared tag is what makes it a discriminated union.

ts
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "triangle"; base: number; height: number };
function area(s: Shape) {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.radius ** 2;
    case "square":
      return s.side ** 2;
  }
}

2. switch

Inside a switch on s dot kind, TypeScript narrows the type for us. In the circle case it knows there is a radius, and in the square case a side. We try a circle with radius two.

ts
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "triangle"; base: number; height: number };
function area(s: Shape) {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.radius ** 2;
    case "square":
      return s.side ** 2;
  }
}
bash
$ node src/shapes2.ts

3. Forgot

But we forgot the triangle. Node does not complain. The function returns undefined, and the bug hides quietly in the output.

ts
console.log(area({ kind: "triangle", base: 4, height: 3 }));
bash
$ node src/shapes2.ts

4. never

We make TypeScript find such mistakes. In a default case we assign s to a variable of type never. Never means: this can never happen. If all kinds are handled, s really is never.

bash
$ npx tsc --noEmit

5. Error

And tsc reports it: the triangle type is not assignable to type never. TS2322. The error shows exactly which kind we forgot.

6. Fix

We add the case for the triangle. Now every kind is handled, tsc is quiet, and the area is six.

bash
$ npx tsc --noEmit

7. Why

When we add a new kind later, tsc will point to every switch that needs a new case. That is the real power of this pattern.

Recap

Today: a shared tag property, switch narrowing, and never to check that we handled every case. Next episode: any, unknown and satisfies.

ยฉ 2026 All Rights Reserved By Mahmudul Alam