Type guards are a feature in TypeScript that allows you to narrow down the type of a variable within a conditional block, ensuring the variable has a specific type. With type guards, you can write more robust and type-safe code.
In TypeScript, type guards can be created using:
1. ‘typeof‘ type guard
2. ‘instanceof‘ type guard
3. User-defined type guards
Let us discuss these three ways of creating type guards with examples.
### 1. ‘typeof‘ Type Guard
The ‘typeof‘ type guard is useful when we want to narrow down the type of a variable based on the variable’s value.
function example(value: string | number): string {
if (typeof value === "string") {
// The type of 'value' is narrowed to 'string'
return `String: ${value.toUpperCase()}`;
} else {
// The type of 'value' is narrowed to 'number'
return `Number: ${value.toFixed(2)}`;
}
}
We use the ‘typeof‘ keyword followed by the value, and then we make an equality comparison to the desired type as a string.
text{if }(text{typeof value === "string"}) {
quad text{// The type of 'value' is narrowed to 'string'}
}
### 2. ‘instanceof‘ Type Guard
The ‘instanceof‘ type guard is useful when you want to narrow down the type of a variable based on the variable’s instance.
class Animal {
makeSound(): string {
return "Unknown sound";
}
}
class Dog extends Animal {
makeSound(): string {
return "Woof";
}
}
class Cat extends Animal {
makeSound(): string {
return "Meow";
}
}
function speak(animal: Animal): string {
if (animal instanceof Dog) {
// 'animal' is narrowed from 'Animal' to 'Dog'
return `Dog says: ${animal.makeSound()}`;
}
if (animal instanceof Cat) {
// 'animal' is narrowed from 'Animal' to 'Cat'
return `Cat says: ${animal.makeSound()}`;
}
return `Animal says: ${animal.makeSound()}`;
}
We use the ‘instanceof‘ keyword followed by the variable and the class we want to compare it to.
(animal Dog) {
}
### 3. User-defined Type Guards
User-defined type guards allow you to create your own type guard functions to narrow down the types based on custom conditions. The syntax for user-defined type guards is:
function isType(value: any): value is Type
Here’s an example of using a user-defined type guard:
interface Bird {
fly(): string;
layEggs(): string;
}
interface Fish {
swim(): string;
layEggs(): string;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function move(pet: Fish | Bird): string {
if (isFish(pet)) {
// 'pet' is narrowed from 'Fish | Bird' to 'Fish'
return pet.swim();
} else {
// 'pet' is narrowed from 'Fish | Bird' to 'Bird'
return pet.fly();
}
}
Here, we use ‘pet is Fish‘ in the function signature, which checks if ‘pet‘ is of type ‘Fish‘.
In summary, type guards in TypeScript help you narrow down the types of variables in conditional blocks using ‘typeof‘, ‘instanceof‘, or user-defined type guards, making your code more robust and type-safe.