Narrowing — how typeof, in and instanceof change a type¶
Level: 201 · for TypeScript users working with union types
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The questions below are what the finished page has to answer.
One line: 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'.
Keywords: narrowing, type guard, control flow analysis
What the finished page will answer¶
- What type does
valuehave aftertypeof value === "object", and why isnullstill in it (TS18047)? - How do an early
returnand anelsenarrow the code that follows, and what doinandinstanceofnarrow to? - Does a test stored in a constant,
const isText = typeof x === "string", still narrowxinsideif (isText)? - Does narrowing survive into a callback, for a parameter that is never reassigned and for a
letthat is reassigned later? - Which other tests narrow:
Array.isArray,x === undefined,x == null, aswitch (typeof x)?
Examples it will need¶
-
narrowing_typeof_null_tserror.ts— TS18047 for a property read aftertypeof value === "object", and no errors on the string, number and Date branches -
narrowing_aliases_and_callbacks_tserror.ts— the narrowed types seen through an aliased test and inside callbacks, printed through deliberate TS2322 errors -
narrowing_in_and_instanceof_ts.ts— one line per input value, naming the branch thattypeof,inandinstanceofsent it to
See also¶
typeof— the run-time operator the checker reads,nullquirk includedinstanceof— whatinstanceofchecks at run time- Own and inherited properties — the
inoperator, which also finds inherited keys - Truthiness narrowing — the test that narrows and also turns away
0and"" - Union and intersection types — the unions that narrowing takes apart
- Rust:
if let: one arm, and move on ↗ — narrowing by pattern instead of by test, with Rust'sif let