Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The instanceof operator is a built-in runtime type guard that tests whether the prototype property of a constructor function or class appears anywhere in the prototype chain of an object. In TypeScript, it integrates directly with the compiler’s control flow analysis to narrow the static type of a variable within a specific lexical scope.
object instanceof constructor

Type Narrowing Mechanics

When evaluated inside a conditional statement, TypeScript leverages instanceof to refine a broader type (such as unknown, any, or a union type) down to the specific class type.
class BaseEvent {
    timestamp: number = Date.now();
}

class CustomMouseEvent extends BaseEvent {
    x: number = 0;
    y: number = 0;
}

function processEvent(event: BaseEvent | CustomMouseEvent) {
    if (event instanceof CustomMouseEvent) {
        // Type is narrowed to CustomMouseEvent
        // event.x and event.y are safely accessible
        console.log(event.x, event.y);
    } else {
        // Type is narrowed to BaseEvent
        console.log(event.timestamp);
    }
}

Technical Constraints and Limitations

1. Type Erasure Incompatibility Because instanceof is a JavaScript runtime operator, the right-hand operand must be a value that exists at runtime (e.g., a class or a constructor function). It cannot be used with TypeScript-exclusive constructs like interface or type aliases, as these are erased during compilation.
interface User {
    name: string;
}

declare const data: unknown;

// ❌ Compilation Error: 'User' only refers to a type, but is being used as a value here.
if (data instanceof User) { } 
2. Primitive Values TypeScript restricts primitive types on the left-hand side of the instanceof operator. According to the ECMAScript specification, instanceof immediately returns false if the left-hand operand is not an object, regardless of auto-boxed prototype chains. To prevent dead code and logical errors resulting from this guaranteed false evaluation, the TypeScript compiler rejects instanceof checks on strict primitive types. A primitive type is only permitted on the left-hand side if it is part of a union type that also includes an object type, or if the variable is explicitly typed as any or unknown.
const literalString = "hello";
const objectString = new String("hello");

// ❌ Error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.
literalString instanceof String; 

// ✅ Valid: objectString is an object type
objectString instanceof String;  

// ✅ Valid: primitive is part of a union containing an object type
function checkValue(value: string | Date) {
    if (value instanceof Date) {
        // TypeScript narrows `value` to Date
        console.log(value.getTime());
    } else {
        // TypeScript narrows `value` to string
        console.log(value.toUpperCase());
    }
}
3. Cross-Realm Execution instanceof can yield false negatives when evaluating objects across different execution realms (such as iframes or Node.js vm modules). An Array created in one iframe will not evaluate to true against the Array constructor of the parent window, because each realm maintains its own distinct global object and prototype chain.

Customizing instanceof Behavior

Modern JavaScript allows overriding the default prototype-checking behavior of instanceof by implementing the Symbol.hasInstance method on the constructor. Since TypeScript 5.3, Symbol.hasInstance can be defined with a type predicate (e.g., instance is Type). This ensures that the compiler’s control flow analysis directly follows the custom runtime logic, providing a type-safe way to narrow objects that do not strictly share a prototype chain.
class Validator {
    isValid!: boolean;

    // Type predicate ensures TS narrows the type correctly based on custom logic
    static [Symbol.hasInstance](instance: unknown): instance is Validator {
        return typeof instance === "object" && instance !== null && "isValid" in instance;
    }
}

declare const mockObj: unknown;

if (mockObj instanceof Validator) {
    // TypeScript safely narrows `mockObj` to type `Validator`
    // mockObj.isValid is statically known and accessible
    console.log(mockObj.isValid);
}
Master TypeScript with Deep Grasping Methodology!Learn More