BeCuriouzLearn something new every day
instanceof & in: Narrowing by Class and by Key
💡 Use instanceof to narrow class instances by their prototype and in to narrow object shapes by which property key they have.
Recall from card #1 that narrowing is how TypeScript shrinks a broad type down to a more specific one inside a branch of code. typeof handles primitives, but it can't tell one object or class apart from another — every object is just "object". Two operators fill that gap: instanceof and in.
The instanceof guard checks whether a value was created from a particular class (technically, whether the class's prototype sits in the value's prototype chain). Inside the true branch, TypeScript narrows the variable to that class type, so its methods and fields become available:
function logDate(x: Date | string) {
if (x instanceof Date) {
console.log(x.getFullYear()); // x: Date
} else {
console.log(x.toUpperCase()); // x: string
}
}The in operator narrows by asking whether a property key exists on an object — perfect for plain object shapes that aren't class instances. If one member of a union has a key the others lack, in distinguishes them:
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim(); // animal: Fish
} else {
animal.fly(); // animal: Bird
}
}Rule of thumb: reach for instanceof when your values come from real classes (like Date, Error, Map, or your own), and reach for in when you're distinguishing plain object literals by which properties they carry.