DAY 15 OF 30
Type guards
Yesterday, in one sentence
When TypeScript works out from your code that a value must be one specific type in that part of the program.
Did you say:
- ✓TypeScript works out the specific type from your code
- ✓applies to that part of the program
Interview question
string | number, how would you safely call a string method on it?Narrow it first. Check typeof value === "string", and inside that branch
TypeScript knows it is a string, so the method is allowed.
Did you say:
- ✓narrow it first
- ✓check `typeof value === "string"`
- ✓the narrowed type applies inside the branch
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
value to string at the call site?
function isName(value: string | number) {
return typeof value === "string"
}
A type predicate, written value is string, tells TypeScript that a true return means the argument is a string. A plain boolean return type narrows nothing.
A check that narrows a type. typeof, in and an if comparing against
undefined are built in, and you can write your own function with a type
predicate return type like value is string.
Did you say:
- ✓a check that narrows a type
- ✓`typeof`, `in` and `undefined` checks are built in
- ✓you can write your own with a type predicate return type