TypeScript Intermediate: Generics and Utility Types
Type Guards and Discriminated Unions
In this lesson you will
- Model alternatives with a discriminated union
- Write exhaustive switch statements with never
- Write a custom type guard and validate unknown data
Introduction
Think of a payment: it could be by card, by bank transfer, or in cash, and each has different details. You could use one big object with lots of optional properties, but then nothing stops invalid combinations like cash with a card number. A better tool is a discriminated union.
The problem with optional fields
Everything is optional, so TypeScript can't know which fields exist. The code is full of checks, and wrong objects such as a circle with a width are still allowed.
A discriminated union
Make each alternative its own type, with a shared property (the discriminant) holding a unique literal value.
Checking s.kind narrows the type. Inside each branch you can use exactly the fields that exist. No optional fields, no guessing.
Quick quiz
What is the discriminant in a discriminated union?
Exhaustive checks with never
The type never means "this can never happen". Use it to force a handled case for every member of the union. If a new shape is added later, the compiler tells you everywhere you forgot it.
Add a case "triangle": returning (s.base * s.height) / 2 and the error disappears. That is a compile-time safety net for the future.
Custom type guards
A type guard is a function whose return type tells TypeScript how to narrow. Write value is Type:
TypeScript trusts the guard, so make sure its check is accurate.
Validating unknown data
Data from outside your program, such as parsed JSON, is unknown. A guard turns it into a trusted type, after checking.
TypeScript types disappear at runtime, so they cannot check data arriving from a server or a file. Guards, or a validation library, fill that gap.
Quick quiz
What does the return type pet is Cat tell TypeScript?
Try it yourself
The function show must handle every kind of State, but the compiler complains because the "error" case is missing. Add it so that it returns "Error: " followed by the message, then check that the complaint disappears.
Summary
- A discriminated union gives each alternative its own type and a shared literal property to tell them apart.
- Checking the discriminant narrows the type, and
nevermakes the compiler check every case. - A type guard
value is Typelets your own function narrow types. - Validate
unknowndata from outside your program before trusting it.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading