24 — Narrowing¶
One line: After a test that only some members of a union can pass, the checker shrinks the variable's type inside that branch; the chapter is about which tests it understands, which it takes on trust, and how to make it prove no case was forgotten.
Narrowing makes a union usable: the checker reads typeof, in, instanceof and equality tests and shrinks the type in each branch. The chapter starts with those built-in tests and with truthiness, the test that also turns away 0 and "". It then builds unions meant to be narrowed, discriminated by a tag, and uses never to catch a forgotten case. It ends with the tests you write yourself, type predicates and assertion functions, which the checker trusts without looking, and with satisfies, as and annotations.
The pages¶
| Page | Level | In one line | Status |
|---|---|---|---|
| Narrowing | 201 | After if (typeof value === "string") return, the rest of the function knows value is not a string; but typeof value === "object" also lets null through, so reading value.tags in that branch is TS18047, 'value' is possibly 'null'. |
stub |
| Truthiness narrowing | 201 | if (count) narrows number | null to number, which reads as 'not null', but at run time 0 fails the test too: label(0) prints no count, and only the type after the if, still number | null, hints that a number can arrive there. |
stub |
| Discriminated unions | 201 | A union narrows on a tag only when each member's tag is a literal type: with kind: "circle" and kind: "square", switch (shape.kind) gives each case its member, even through const { kind } = shape; with kind: string, reading radius is TS2339. |
stub |
| Exhaustiveness checking | 201 | Once every member of a union has its case, what reaches default is never; assign it to a never variable there, and adding a triangle member later turns the forgotten case into TS2322 on that line, naming the triangle type. |
stub |
| Type predicates | 201 | The checker takes a type predicate on trust: isString(value): value is string that returns true for 42 compiles cleanly, so input.toUpperCase() passes the check and throws a TypeError at run time. |
stub |
satisfies, as and annotations |
201 | An annotation checks an object and forgets its details, satisfies checks it and keeps them, and as barely checks: { red: [255, 0, 0] } as Palette compiles without the required green, which satisfies Palette reports as TS2741. |
stub |
Boundaries¶
Unions and literal types are introduced in Everyday types; the assertions that lie outright, as and the postfix !, are shown failing in Where types lie.