Type Assertions and Type Guards
Sometimes TypeScript needs help understanding the specific type of a value. Type assertions and type guards help us tell TypeScript exactly what we're working with.
Type Assertions
Type assertions are like telling TypeScript "trust me, I know what this is":
// Using 'as'
const myCanvas = document.getElementById('main_canvas') as HTMLCanvasElement;
// Using angle-bracket syntax (not used in TSX files)
const myCanvas2 = <HTMLCanvasElement>document.getElementById('main_canvas');
Type Guards
Type guards are runtime checks that guarantee the type in a certain scope:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function processValue(value: unknown) {
if (isString(value)) {
// TypeScript knows value is a string here
console.log(value.toUpperCase());
}
}
Common Type Guards
typeof
function printValue(value: string | number) {
if (typeof value === "string") {
// TypeScript knows value is a string
console.log(value.toUpperCase());
} else {
// TypeScript knows value is a number
console.log(value.toFixed(2));
}
}
instanceof
class Car {
drive() { /* ... */ }
}
class Bicycle {
pedal() { /* ... */ }
}
function operate(vehicle: Car | Bicycle) {
if (vehicle instanceof Car) {
vehicle.drive();
} else {
vehicle.pedal();
}
}
Discriminated Unions
A common pattern using type guards:
type Circle = {
kind: "circle";
radius: number;
};
type Square = {
kind: "square";
sideLength: number;
};
type Shape = Circle | Square;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.sideLength ** 2;
}
}
Best Practices
- Avoid type assertions when possible
- Use type guards for better type safety
- Make discriminated unions explicit
- Keep type guards simple and focused
Practice Exercise
Create a function that processes different types of user input (string, number, or boolean) and returns appropriate responses using type guards.