Narrowing in Typescript

Typescript has union types which according to the Typescript handbook are a type formed from two or more other types representing values that may be any of those types. Unions in Typescript are created using the pipe operator e.g

type ID = string | number;

Trying to use access a property or call a method that only occurs in one of the types causes an error.

function lowerCasedEmailorId(id: ID) {
  return id.toLowerCase();
}

Typescript will complain that toLowerCase does not exist on type number.

To fix this we need to use narrowing. Narrowing is where Typescript figures out a more specific type for a value based on the structure of our code.

In our example since id can be a string or number to use it, we have to only use properties/functions that are common to both types or conditionally check the type before using a property that occurs in one type only.

function fetchUserByEmail(email: string) {}
function fetchUserById(id: string) {}

function fetchUser(id: ID) {
  // check if id is a string
 if (typeof id === "string") {
   return fetchUserByEmail(id);
 }
 return fetchUserById(id);
}

In the above case, Typescript can figure out that id in the if block will be a string.

If a property or method is common in the types that make up the union then narrowing is not necessary.

const value = id.toString();