Skip to content

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 value have after typeof value === "object", and why is null still in it (TS18047)?
  • How do an early return and an else narrow the code that follows, and what do in and instanceof narrow to?
  • Does a test stored in a constant, const isText = typeof x === "string", still narrow x inside if (isText)?
  • Does narrowing survive into a callback, for a parameter that is never reassigned and for a let that is reassigned later?
  • Which other tests narrow: Array.isArray, x === undefined, x == null, a switch (typeof x)?

Examples it will need

  • narrowing_typeof_null_tserror.ts — TS18047 for a property read after typeof 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 that typeof, in and instanceof sent it to

See also

Sources to start from