Module 27: TypeScript Foundations
Union types and narrowing
🏠The everyday picture
A parking space marked "cars or motorbikes". Before parking, the attendant checks which one you've brought, because they're handled differently.
📘What it really is
- A union type allows one of several types, written with
|:
let id: string | number;
type Status = "pending" | "paid" | "cancelled";
let orderStatus: Status = "paid";
The second form, a union of exact text values (literal types), is extremely useful: misspelling
"payed" is now an error.
- Before using a union value in a way that only suits one type, narrow it with a check:
function formatId(id: string | number): string {
if (typeof id === "number") {
return `#${id.toString().padStart(4, "0")}`;
}
return id.toUpperCase();
}
Inside the if, TypeScript knows id is a number; after it, a string.
-
Missing values: with
stricton,nullandundefinedmust be part of the type to be allowed:let note: string | undefined;. TypeScript then makes you handle the missing case, preventing the "Cannot read properties of undefined" error at its source. -
findreturnsProduct | undefined, so TypeScript insists you check before using the result. That's a real bug caught before it happens.
🖱️Try it
Define type Category = "Stationery" | "Books" | "Bags";. Write findProduct(products, id) that returns the
product or undefined, and a caller that prints the product's name. TypeScript will complain until you handle
the "not found" case. Handle it.
✅Quick check
What does type Size = "S" | "M" | "L" prevent?
Show the answer
Any other value, including typos like "m" or "XL", as a size.
Why does TypeScript complain about products.find(...).name?
Show the answer
find might return undefined; you must check that a product was found before reading its name.
