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.
- All episodes are in the TypeScript from Zero playlist.
- Versions used: Node.js 26.13.0, npm 11.20.0, TypeScript 7.0.2.
Setup
We start in the terminal and open the project in VS Code:
$ touch src/shapes2.ts1. 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.
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.
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;
}
}$ node src/shapes2.ts3. Forgot
But we forgot the triangle. Node does not complain. The function returns undefined, and the bug hides quietly in the output.
console.log(area({ kind: "triangle", base: 4, height: 3 }));$ node src/shapes2.ts4. 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.
$ npx tsc --noEmit5. 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.
$ npx tsc --noEmit7. 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.