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

DAY 15 OF 30

Type guards

Yesterday, in one sentence

What is type narrowing in TypeScript?

Interview question

Given a value typed as string | number, how would you safely call a string method on it?

A type guard is a check that narrows a type. Everything from the last lesson was a type guard: typeof, in, and using if to compare against undefined.

You can also write your own type guard as a function, for checks TypeScript cannot work out on its own. You might try to do it like this, but this does not work.

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

function isHero(character: Hero | Villain) {
  return "power" in character;
}

function act(character: Hero | Villain) {
  if (isHero(character)) {
    character.power;
    // ❌ Property 'power' does not exist on type 'Hero | Villain'
  }
}

The check itself is correct, but TypeScript only sees that isHero returns a boolean. It has no way of knowing that a true means the argument was a Hero.

You tell it by writing the return typeReturn Type as character is Hero. This is called a type predicate, and it says that when the function returns true, that argument is that type. The is keyword only appears here, as the return type of a function, and cannot be used anywhere else.

function isHero(character: Hero | Villain): character is Hero {
  return "power" in character;
}

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

The predicate is a claim you are making, not something TypeScript checks. If the body returns true for a value that is not a Hero, TypeScript believes you and the narrowing is wrong.

Check yourself

Which return type makes this function narrow value to string at the call site?
function isName(value: string | number) {
  return typeof value === "string"
}
What is a type guard in TypeScript? Give some examples.