260

I wrote this code

interface Foo {
    abcdef: number;
}

let x: Foo | string;

if (x instanceof Foo) {
    // ...
}

But TypeScript gave me this error:

'Foo' only refers to a type, but is being used as a value here.

Why is this happening? I thought that instanceof could check whether my value has a given type, but TypeScript seems not to like this.

4

6 Answers 6

222

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: C = {
    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.

2
  • 3
    So basically I didn't get the idea from the answer which is better to go with. Class? because you detailed it. But confused at the same time as you mentioned "you maybe tempted". So what if I have to compare all properties and not just swim property as in docs for type guards?
    – HalfWebDev
    Commented Jan 11, 2019 at 13:58
  • 48
    The main point here is that instanceof works with classes, not interfaces. Thought that needed to be emphasized.
    – inorganik
    Commented Jun 7, 2019 at 14:33
36

To do type checking at runtime with an interface is using type guards, if interfaces you wish to check have different properties/functions.

Example

let pet = getSmallPet();

if ((pet as Fish).swim) {
    (pet as Fish).swim();
} else if ((pet as Bird).fly) {
    (pet as Bird).fly();
}
3
  • 1
    What if I learn about ducks and add the function swim() to my Bird interface? Would't every pet be classified as fish in a type guard? And if I have three interface with three functions each and two overlap with one of the other interfaces?
    – Kayz
    Commented Jul 15, 2020 at 14:49
  • 2
    @Kayz if you don't have properties/functions that uniquely identify an interface, you can't really differentiate them. Your pet that could be actually a Duck, you type guard it becomes Fish, but still no runtime exception when you invoke swim(). Suggest you create 1 level of common interface (e.g. Swimmable) and move you swim() functions there, then type guard still looks good with ((pet as Swimmable).swim. Commented Jul 19, 2020 at 2:48
  • 2
    To prevent typecasting you can use 'swim' in pet condition. It will narrow it down to a subset that has to have swim defined (ex: Fish | Mammal)
    – Akxe
    Commented Oct 12, 2020 at 11:15
4

When it is about checking if an object conforms to an interface signature, then I think the appropriate approach is considering using "type predicates": https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates

3

Daniel Rosenwasser might be right and dandy but i feel like doing an amendment to his answer. It is fully possible to check instance of x, see the code snippet.

But it's equally easy to assign x = y. Now x would not be an instance of C as y only had the shape of C.

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

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

console.log('x is C? ' + (x instanceof C)) // return true
console.log('y is C? ' + (y instanceof C)) // return false
0

You can use the in operator narrowing for checking if the element you need is in the object.

With this method, you can verify if x is a string or Foo

if ('abcdef' in x) {
    // x is instance of Foo
}
0

instanceof is usually the correct answer.

In my case however, I was working with a primitive type and both instanceof Number and instanceof number errored in the ts compiler:

TS2322: Type 'Number' is not assignable to type 'number'.
TS2693: 'number' only refers to a type, but is being used as a value here.

typeof is the correct answer when primitive types are in use:

if (typeof value === 'number') {this.propertyValue = value}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.