Why does ‘instanceof’ in TypeScript give me the error “‘Foo’ only refers to a type, but is being used as a value here.”?

TL;DR

instanceof works with classes, not interfaces nor type aliases.


What’s TypeScript trying to tell me?

The issue is that instanceof is a construct from JavaScript, and in JavaScript, instanceof expects a value for the right-side operand.
Specifically, in x instanceof Foo JavaScript will perform a runtime check to see whether Foo.prototype exists anywhere in the prototype chain of x.

However, in TypeScript, interfaces have no emit. The same is true of type aliases. That means that neither Foo nor Foo.prototype exist at runtime, so this code will definitely fail.

TypeScript is trying to tell you this could never work. Foo is just a type, it’s not a value at all!

If you’re coming from another language, you might have meant to use a class here. Classes do create values at runtime, but there are some notes about that that you may want to read about below.

“What can I do instead of instanceof if I still want a type or interface?”

You can look into type guards and user-defined type guards.

“But what if I just switched from an interface to a class?”

You might be tempted to switch from an interface to a class, but you should realize that in TypeScript’s structural type system (where things are primarily shape based), you can produce any an object that has the same shape as a given class:

class C {
    a: number = 10;
    b: boolean = true;
    c: string = "hello";
}

let x = new C()
let y = {
    a: 10, b: true, c: "hello",
}

// Works!
x = y;
y = x;

In this case, you have x and y that have the same type, but if you try using instanceof on either one, you’ll get the opposite result on the other. So instanceof won’t really tell you much about the type if you’re taking advantage of structural types in TypeScript.

Leave a Comment