Type narrowing and discriminating unions in TypeScript

Tuesday, May 10, 2022

Type narrowing is the process of moving from a less precise set of types to a more precise type or set of types. The aim of type narrowing is to reduce the types down to only the ones where the following methods or properties can be correctly accessed or called without throwing errors.

It's a bit like playing a game of "Twenty questions".

In the traditional game, one player is chosen to be the answerer. That person chooses a subject but does not reveal this to the others. All other players are questioners. They each take turns asking a question which can be answered with a simple "yes" or "no". - https://en.wikipedia.org/wiki/Twenty_questions

Consider a variable that can be a string, number or Date.

If we want to format that variable, then we need to know what it is in order to do so. We need to apply some narrowing inside the function so that we can handle the different types which the variable can be.

This also works with properties of types. Take the following function, which allows you to add a flavor to your snack.

Because we can pass a Sandwich or a Pizza to the addFlavor function, TypeScript throws an error when we try to access the .topping property because we could be trying to access a topping on a Sandwich which is not possible. In order to prevent this from happening we need to narrow the type down to just Pizza (or Snacks which can have a topping).

By using the values and properties of variables and objects we can narrow down the type until we get to one or more that we are targetting.

We can ask the question... Do you have a property of topping? And if the answer is "yes" then we perform our actions.

Now if we add a new type of snack then the same logic can apply

We can also use combinations of properties to discriminate between types, or use discrimination unions.

Discriminating unions

One way to narrow down the type on which TypeScript is working with is to add a literal field to all relevant types and use it to narrow down to a single type.

Because types are removed during the build step of TypeScript we can't use the type names directly, instead we have to add another property to use in order to distinguish between them at run time

By using a discriminating union pattern we have a good way to narrow our types easily, especially where there are many other common overlapping properties.

Other posts

Tagged with: