Welcome back! I am Mihir, and in this lesson we will learn instanceof narrowing in TypeScript.
instanceof checks whether a value was created from a class or constructor function.
Basic instanceof Narrowing
function formatDate(value: Date | string) {
if (value instanceof Date) {
return value.toISOString();
}
return value.toUpperCase();
}Inside the if, TypeScript knows value is a Date.
Outside it, TypeScript knows value is a string.
Narrowing Custom Classes
class Car {
drive() {
console.log("Driving");
}
}
class Bike {
ride() {
console.log("Riding");
}
}
function move(vehicle: Car | Bike) {
if (vehicle instanceof Car) {
vehicle.drive();
} else {
vehicle.ride();
}
}instanceof Car narrows vehicle to the Car class.
instanceof with Error
This is useful in error handling.
function handleError(error: unknown) {
if (error instanceof Error) {
console.log(error.message);
} else {
console.log("Unknown error");
}
}Because catch values can be unknown, instanceof Error is a practical check.
instanceof Needs Runtime Values
instanceof works with classes because classes exist at runtime.
class User {
constructor(public name: string) {}
}
const user = new User("Mihir");
console.log(user instanceof User);This logs:
trueinstanceof Does Not Work with Interfaces
Interfaces do not exist at runtime.
interface User {
name: string;
}You cannot do this:
value instanceof User;User is only a TypeScript type, not a JavaScript runtime value.
Use Property Checks for Interfaces
For interface-like objects, use property checks or type guards.
interface User {
name: string;
}
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"name" in value
);
}Quick Recap
instanceofnarrows class and constructor-based values.- It works well with
Date,Error, and custom classes. - It requires runtime values.
- It does not work with interfaces or type aliases.
- Use property checks for plain objects.
Next up, we will learn Type Guards →.