> ## 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.

# TypeScript Instanceof

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.

```typescript theme={"dark"}
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.

```typescript theme={"dark"}
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.

```typescript theme={"dark"}
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`.

```typescript theme={"dark"}
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.

```typescript theme={"dark"}
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);
}
```

<div
  style={{ 
display: "flex", 
justifyContent: "space-between", 
alignItems: "center", 
maxWidth: "754px", 
padding: "1rem 0",
marginBottom: "24px"
}}
>
  <span style={{ fontWeight: "bold", fontSize: "1.25rem", color: "var(--tw-prose-headings)", fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" }}>Tired of Poor TypeScript Skills? Fix That With Deep Grasping!</span>

  <a
    href="https://syntblaze.com"
    target="_blank"
    style={{ 
  marginLeft: "24px",
  textDecoration: "none", 
  backgroundColor: "#007AFF",
  color: "#ffffff", 
  padding: "6px 16px", 
  borderRadius: "16px",
  fontSize: "0.9rem",
  fontWeight: "600",
  textAlign: "center",
  transition: "background-color 0.2s ease"
}}
  >
    Learn More
  </a>
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/skill-tracking.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=b9b0305c93bb501c9e767b5c76c88835" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/skill-tracking.png" />

  <img src="https://mintcdn.com/syntblazellc/23tyuOzaWS88qFlc/images/nuggets.png?fit=max&auto=format&n=23tyuOzaWS88qFlc&q=85&s=c86c80197299762989e9b882419b2109" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/nuggets.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/bite-sized-exercises.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=a65f9a38c37ff28ab73ed783c53c60e3" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/bite-sized-exercises.png" />
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap", marginTop: "12px" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/mastery-chain.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=748a1763454713e679260fbb95f154a2" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/mastery-chain.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-previews.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=242f61448ff5dd6deaaab2dccc13b507" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-previews.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-explanations.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=cf0fc1c31f9cd0fc26716781be05fbc9" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-explanations.png" />
</div>
