(instanceof) 'X' Only refers to a type, but is being used as a value here

avatar

Borislav Hadzhiev

Last updated: Mar 23, 2022

banner

Photo from Unsplash

(instanceof) 'X' Only refers to a type, but is being used as a value here #

The 'instanceof' error "only refers to a type, but is being used as a value here" occurs when we try to use the instanceof operator with a type instead of a value. To solve the error, create a class instead, or simply use a user-defined type guard.

only refers to type but is being used as value

Here is an example of how the error occurs.

index.ts
interface Employee { name: string; salary: number; } let emp: Employee; // ⛔️ 'Employee' only refers to a type, but is being used as a value here.ts(2693) if (emp instanceof Employee) { console.log(emp.salary); }

The error was caused because we used the instanceof operator with a type instead of a value.

The instanceof operator returns a boolean value indicating whether the prototype property of the constructor appears in the prototype chain of the object.

One way to solve the error is to use a class instead of an interface.

index.ts
class Employee { constructor(public name: string, public salary: number) { this.name = name; this.salary = salary; } } const emp = new Employee('Tom', 100); if (emp instanceof Employee) { // 👇️ this runs console.log('✅ is instance of Employee'); } console.log(emp instanceof Employee); // 👉️ true

The emp object was created using the Employee class, so it is an instance of the class.

Note that you can also set class properties if you don't intend to take parameters when instantiating the class.

index.ts
class Employee { name = ''; salary = 0; tasks: string[] = []; } const emp = new Employee(); emp.name = 'Alice'; emp.salary = 100; emp.tasks.push('test'); if (emp instanceof Employee) { // 👇️ this runs console.log('✅ is instance of Employee'); } console.log(emp instanceof Employee); // 👉️ true

However, note that you can have an object that satisfies the type, but is not an instance of the class, because it wasn't created using the specific class.

index.ts
class Employee { constructor(public name: string, public salary: number) { this.name = name; this.salary = salary; } } // 👇️ Correct type, but not an instance const emp2: Employee = { name: 'James', salary: 200, }; console.log(emp2 instanceof Employee); // 👉️ false const emp = new Employee('Tom', 100); console.log(emp instanceof Employee); // 👉️ true

The emp2 variable is not an instance of the Employee class, even though it satisfies the type. The reason is that it wasn't created using the class.

If you need to test if a specific object correctly implements a type, you can use a user-defined type guard.

index.ts
interface Employee { id: number; name: string; salary: number; } function isAnEmployee(obj: any): obj is Employee { return 'id' in obj && 'name' in obj && 'salary' in obj; } const emp: Employee = { id: 3, name: 'Alice', salary: 300, }; console.log(isAnEmployee(emp)); // 👉️ true console.log(isAnEmployee({ id: 1 })); // 👉️ false if (isAnEmployee(emp)) { // 👉️ TypeScript knows that emp is type Employee console.log(emp.id); // 👉️ 3 console.log(emp.name); // 👉️ "Alice" console.log(emp.salary); // 👉️ 300 }

We used a user-defined type guard to check if an object implements an interface.

The obj is Employee syntax is a type predicate where obj must be the name of the parameter the function takes.

If the isAnEmployee function returns true, TypeScript knows that the passed in value is of type Employee and allows us to access all properties and methods on the specific interface.

The example above simply checks if the passed-in object contains the id, name and salary properties.

This can get pretty verbose if your interface has many properties.

An alternative approach is to add a type property to the interface, for which you check instead.

index.ts
interface Employee { id: number; name: string; salary: number; type: 'Employee'; // 👈️ add type property } function isAnEmployee(obj: any): obj is Employee { // 👇️ check for type property return 'type' in obj && obj.type === 'Employee'; } const emp: Employee = { id: 3, name: 'Alice', salary: 300, type: 'Employee', }; console.log(isAnEmployee(emp)); // 👉️ true console.log(isAnEmployee({ id: 1 })); // 👉️ false if (isAnEmployee(emp)) { console.log(emp.id); // 👉️ 3 console.log(emp.name); // 👉️ "Alice" console.log(emp.salary); // 👉️ 300 console.log(emp.type); // 👉️ "Employee" }

The Employee interface has a type property with the string literal value of Employee. This means that all objects that have a type Employee will have this property.

In our function, all we have to do is check if the passed-in object has a type property that's equal to Employee.

Conclusion #

The 'instanceof' error "only refers to a type, but is being used as a value here" occurs when we try to use the instanceof operator with a type instead of a value. To solve the error, create a class instead, or simply use a user-defined type guard.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.