Type narrowing

Determining a more precise type for a value based on checks in your code.

On this page

Example

#
TypeScript
function total(input: number | number[] | null): number {
  if (input === null) return 0
  if (Array.isArray(input)) return input.reduce((sum, n) => sum + n, 0)
  return input
}

console.log(total(null))
console.log(total(7))
console.log(total([3, 4, 5]))
Result
0
7
12

Definition and usage

#

Narrowing is the mechanism that lets TypeScript know more about a value, within a given block of code, than its declaration alone states. After a check like if (typeof value === "string"), inside that block the variable has the type string, even if it was a union before.

The compiler understands many kinds of checks: typeof, instanceof, the in operator, comparisons with literals, checks against null and undefined, Array.isArray(), and your own type guard functions.

It also works the other way around: after a return in one branch, TypeScript knows that case no longer applies in the rest of the function.

Syntax

#
Syntax
if (typeof value === "string") {
  // value: string
}

Good practices

#
  • An early return for edge cases (null, an empty array) simplifies the rest of the function, because the type is already narrowed.
  • When a check gets complex, extract it into a type guard function with the type value is T.

Related entries

#

Spotted a mistake or missing an example? Write to us.