instanceof Narrowing
While typeof narrows primitives, the instanceof operator narrows values that come from classes or constructor functions. It checks whether an object’s prototype chain includes a given constructor’s prototype, and TypeScript uses that check to refine the static type inside the branch. This makes instanceof the natural tool for unions of class instances, built-in objects like Date and Error, and any value created with new. This page covers basic usage, error handling, inheritance, and the limits of instanceof.
The instanceof type guard
When a value can be one of several class instances, x instanceof SomeClass narrows it to that class within the truthy branch.
class Dog {
bark() {
return "Woof";
}
}
class Cat {
meow() {
return "Meow";
}
}
function speak(animal: Dog | Cat): string {
if (animal instanceof Dog) {
// animal: Dog
return animal.bark();
}
// animal: Cat
return animal.meow();
}
The right-hand side of instanceof must be a constructor function. TypeScript narrows the left side to the instance type of that constructor, so the class-specific methods become available.
Narrowing unknown and error handling
A catch clause in TypeScript types its variable as unknown (with useUnknownInCatchVariables on, the default under strict). instanceof is the idiomatic way to recover a useful type.
async function load(url: string): Promise<string> {
try {
const res = await fetch(url);
return await res.text();
} catch (err: unknown) {
if (err instanceof Error) {
// err: Error
return `Failed: ${err.message}`;
}
return "Unknown failure";
}
}
Because anything can be thrown in JavaScript — not just Error objects — the unknown type forces you to check before touching .message, and instanceof Error is exactly that check.
Built-in objects
instanceof works with built-in constructors, which is the cleanest way to distinguish, say, a Date from a string or a RegExp from a plain object.
function toISO(value: Date | string): string {
if (value instanceof Date) {
// value: Date
return value.toISOString();
}
// value: string
return new Date(value).toISOString();
}
Inheritance and the prototype chain
Because instanceof walks the prototype chain, a subclass instance satisfies instanceof checks for all of its ancestors. Order your checks from most specific to least specific.
class HttpError extends Error {
constructor(public status: number, message: string) {
super(message);
}
}
function report(err: Error): string {
if (err instanceof HttpError) {
// err: HttpError — check the subclass first
return `HTTP ${err.status}: ${err.message}`;
}
// err: Error
return err.message;
}
| Operator | Narrows | Works on |
|---|---|---|
typeof | primitives | string, number, etc. |
instanceof | class instances | anything with a prototype chain |
in | object shape | presence of a property |
instanceofis a runtime check, so it cannot narrow interfaces or type aliases — those have no constructor and are erased during compilation. Use a custom type guard for interface-only shapes.
When instanceof fails
instanceof compares against a specific constructor identity. Across different execution realms (iframes, worker threads, or separate module instances) the same logical class can have two distinct constructors, so the check returns false unexpectedly.
// In a browser, an array from another iframe:
// frameArray instanceof Array -> false (different realm)
// Prefer a structural check instead:
if (Array.isArray(value)) {
// value: unknown[]
}
For cross-realm values, prefer realm-agnostic helpers like Array.isArray or custom guards over instanceof.
Best Practices
- Use
instanceofto narrow unions of class instances and built-ins likeDate,Error, andRegExp. - In
catchblocks, guard theunknownerror withinstanceof Errorbefore reading its properties. - Check subclasses before their parents, since prototype-chain matching is inclusive.
- Do not use
instanceoffor interfaces or type aliases — they have no runtime constructor. - Prefer
Array.isArrayovervalue instanceof Arrayfor robustness across realms. - Combine
instanceofwithtypeofand custom guards when a single operator cannot fully discriminate the union.