Want a faster signal before interviews? Take the Interview Ready Check →

DAY 14 OF 30

Narrowing in TypeScript

Yesterday, in one sentence

How do you add types to a function in TypeScript?

Interview question

How do you define a function with optional parameters, and what will the type be?

A union typeUnion Type says a value could be one of several types. When passed as a function parameter, TypeScript does not know which one it is yet, so it reports an error on anything that would fail for one of them.

function describe(id: string | number) {
  id.toUpperCase();
  // ❌ Property 'toUpperCase' does not exist on type 'string | number'
  //    id might be a number, and numbers have no toUpperCase method
}

Narrowing is when TypeScript works out from your code that a value must be one specific type in that part of the program. Once you have narrowed the type, TypeScript allows you to use it.

You can use typeof to return a string describing the value's type, and TypeScript narrows from that check. This is known as a type guard, which is covered in the next lesson.

function describe(id: string | number) {
  if (typeof id === "string") {
    id.toUpperCase(); // id is string here
  } else {
    id.toFixed(2); // id is number here
  }
}

The in operator checks whether a property name exists on a value, which narrows an object typeObject Type.

type Hero = { power: string };
type Villain = { scheme: string };

function act(character: Hero | Villain) {
  if ("power" in character) {
    character.power; // character is Hero here
  } else {
    character.scheme; // character is Villain here
  }
}

Checking for undefined narrows too, which is how you handle an optional property or parameter.

function recruit(team?: string) {
  if (team === undefined) return;
  team.toUpperCase(); // team is string here
}

Check yourself

What is the type of value on the marked line?
function show(value: string | number | boolean) {
  if (typeof value === "number") return
  if (typeof value === "boolean") return
  value   // ← here
}
What is type narrowing in TypeScript?