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

avatar
Borislav Hadzhiev

Last updated: Feb 29, 2024
3 min

banner

# (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); }

x only refers to type but is being used as value

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.

# Use instanceof with a class instead

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('Bobby Hadz', 100); if (emp instanceof Employee) { // ๐Ÿ‘‡๏ธ this runs console.log('โœ… is instance of Employee'); } console.log(emp instanceof Employee); // ๐Ÿ‘‰๏ธ true

use instanceof with class instead

The code for this article is available on GitHub

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

# Setting class properties

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 = 'Bobby Hadz'; 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

setting class properties correctly

The code for this article is available on GitHub

However, you can have an object that satisfies the type but isn't 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: 'Bobby Hadz', 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.

# Using a user-defined type guard instead of instanceof

If you need to test if a specific object correctly implements a type, 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: 'Bobby Hadz', 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); // ๐Ÿ‘‰๏ธ "Bobby Hadz" console.log(emp.salary); // ๐Ÿ‘‰๏ธ 300 }

using user defined type guard instead of instanceof

The code for this article is available on GitHub

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.

# Adding a type property to the interface

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: 'Bobby Hadz', 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); // ๐Ÿ‘‰๏ธ "Bobby Hadz" console.log(emp.salary); // ๐Ÿ‘‰๏ธ 300 console.log(emp.type); // ๐Ÿ‘‰๏ธ "Employee" }
The code for this article is available on GitHub

The Employee interface has a type property with the string literal value of Employee. This means that all objects that have a type of 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.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

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.

Copyright ยฉ 2024 Borislav Hadzhiev