Narrowing

Narrowing is proving which branch you are in, and there is no special syntax for it. Ordinary JavaScript checks do the work, and the compiler follows along.

typeof for primitives. === null for null. in for whether a property exists. Array.isArray. instanceof. A truthiness check. All of them narrow.

Try it

Delete the first if in show and watch two errors appear. Then put it back and change it to if (!value) and consider what that does to the empty string.

loading editor…

checking…

No errors. Each check tells the compiler something, and the type on the next line reflects it. The last line of show knows value is a number without being told.

An early return narrows everything after it, which is why guard clauses read so well in TypeScript. Handle the awkward cases first, return, and the rest of the function is working with a known type.

Truthiness narrowing has a trap. if (s) excludes null, undefined and the empty string. For a string | null, that is usually fine and occasionally the bug: a legitimately empty string takes the wrong branch.

◈ Graded Types

Write a function called display that takes a value of type string | number | null and returns a string. For null, return "unknown". For a string, return it upper-cased. For a number, return it with exactly two decimal places, as toFixed(2) gives. It must type-check in strict mode with no assertions and no any.

Checked against the compiler, not against how you wrote it. 4 visible and 2 hidden checks.

loading editor…
real tsc, strict mode

Mark this lesson complete

Signed in, your progress follows you to every device.

Next: Practice Test →
← Back