Type guards are a way to check the type of a variable. Specifically a way for the compiler to narrow the type of a variable. This help the compiler check for errors.
There 3 major types
- typeof
- instanceof
- user defined
Let's look at examples
typeof
type guard
let num = string | number;
if(typeof num === 'number') {
// x is a number. we can can any number methods without getting errors from the compiler
}
In the snippet above the variable num
could be of 2 types, string or number. To perform certain operation to this variable we might need to know the type before performing the operation.
In this case be we use a typeof
type guard using a if statement. Inside the if
block the type of num
is narrowed down to number
.
Note This type is limited to string
, boolean
, number
and symbol
types.
instanceof
type guard
Similar to typeof
type guard, the instanceof
type guard is used to narrow down class instances. Let use an example.
class Dog {
bark() {
console.log('Woof');
}
}
class Cat {
meow() {
console.log('Meow');
}
}
type HousePet = Cat | Dog;
function callOwner(pet: HousePet): void {
if (pet instanceof Dog) {
pet.bark();
} else {
pet.meow();
}
}
In the snippet above the argument pet
of the callOwner
function could be of two types, Dog or Cat. Here two types guard are used to detect the type of the pet before calling the associated method. The if
block us used to check the Dog type while else
block infers that we have a Cat.
User defined type guards
These type guards can be used to check interfaces. To implement user defined type guards we need to implement a function. This function is special because it's signature is different than regular function. This return of this function is called a type predicate. The type predicate has
- the name of the parameter parameter
- followed by 'is'
- followed by the type of the we are checking
Lets look at an example.
interface Car {
horsePower: number;
}
interface Plane {
wings: number;
}
function isCar( c: Car | Plain) c is Car {
return (c as Car).horsePower !== undefined;
}
In the snippet above, we wrote a type guard that checks that a variable is of type Car. This function requires 3 things
- a parameter to check
- The type predicate
- The body of the function perform a check an returns true if the parameter is of the wanted type, otherwise returns false.