instanceof is an operator in TypeScript, which checks if an object is an instance of a specific class or a constructor function. The Instanceof also takes inheritance into account. It returns true if the object inherits from the class’s prototype. instanceof also acts as a Type Guard, helping us infer the type correctly in the scope.
Table of Contents
Using InstanceOf
We use the InstanceOf
operator between the instance and the type want to test. For Example
1 2 3 | obj instanceof class |
It returns true
if the obj
is an instance of the class
, or it appears anywhere in the inheritance chain. Else it will return false
.
For example
1 2 3 4 5 6 7 8 9 10 | class Person { name: string = ''; } let person = new Person(); console.log(person instanceof Person ); // true console.log(person instanceof Object ); // true |
Please note that person
prototypically inherits from Object
, Hence it returns true
It works for most of the types including arrays
, functions
, RegExp
etc
1 2 3 4 5 6 7 8 9 10 11 12 | let arr = [1, 2, 3] console.log(arr instanceof Array); // true let reg: RegExp = new RegExp("/abc/") console.log(reg instanceof RegExp) // true let abc = function abc() { } console.log(abc instanceof Object) // true console.log(abc instanceof Function) // true |
But it will not work on primitive types. It will result in both compile-time and run-time errors.
1 2 3 4 5 6 7 8 9 | let numVar:number = 3 let strVar: string = "Hello" let boolVar: boolean = true console.log(numVar instanceof number) //Error console.log(strVar instanceof string) //Error console.log(boolVar instanceof boolean) //Error |
The left-hand side of an ‘instanceof’ expression must be of type ‘any’, an object type, or a type parameter.
Inheritance
In the above examples, we saw that person instanceof Object
also returns true
. i.e because person
prototypically inherits from Object
To understand let us consider the following example. We have four classes here. Person
is the base class. The Employee
and Customer
extends from the Person
class. The SalesPerson
class extends the Employee
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | class Person { name: string = ''; } class Employee extends Person { } class Customer extends Person { } class SalesPerson extends Employee { } let person = new Person(); let employee = new Employee(); let customer = new Customer(); let salesPerson = new SalesPerson() if (person instanceof Person) console.log("person == Person") //True if (person instanceof Employee) console.log("person == Employee") if (person instanceof Customer) console.log("person == Customer") if (person instanceof SalesPerson) console.log("person == SalesPerson") if (employee instanceof Person) console.log("employee == Person") //True if (employee instanceof Employee) console.log("employee == Employee") //True if (employee instanceof Customer) console.log("employee == Customer") if (employee instanceof SalesPerson) console.log("employee == SalesPerson") if (customer instanceof Person) console.log("customer == Person") //True if (customer instanceof Employee) console.log("customer == Employee") if (customer instanceof Customer) console.log("customer == Customer") //True if (customer instanceof SalesPerson) console.log("customer == SalesPerson") if (salesPerson instanceof Person) console.log("salesPerson == Person") //True if (salesPerson instanceof Employee) console.log("salesPerson == Employee") //True if (salesPerson instanceof Customer) console.log("salesPerson == Customer") if (salesPerson instanceof SalesPerson) console.log("salesPerson == SalesPerson") //True //OUTPUT person == Person employee == Person employee == Employee customer == Person customer == Customer salesPerson == Person salesPerson == Employee salesPerson == SalesPerson |
As you can see from the above result. the employee class return true for both Employee
& Person
class as Employee
inherits from the Person
class. Similarly, salesPerson
class is inherited from the Employee
class, which in turn inherits from the Person
class. Hence it returns true
for both Employee
& Person
.
InstanceOf As Type Guard
Consider the following classes. Customer
& SalesPerson
. Both extend the Person class. Both classes have the common method code()
.They also have additional methods buy()
(Customer class) and sell()
(SalesPerson class)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Person { name: string = ''; } class Customer extends Person { code() { console.log("Customer Code")} buy() { console.log("Bought")} } class SalesPerson extends Person { code() { console.log("SalesPerson Code")} sell() { console.log("Sold")} } |
The following getCode
retrieves the code, which is present in both the classes. We will call the getCode method passing the newly created Customer instance. But Since we are using the Person as the function argument, this code will result in a compiler error Property 'code' does not exist on type 'Person'
1 2 3 4 5 6 7 8 9 | function getCode(obj: Person) { obj.code(); //Property 'code' does not exist on type 'Person' } getCode(new Customer()) |
The one way to solve the problem is to use the converting the obj
into any
as shown below. But using the any
is not an ideal solution.
1 2 3 4 5 6 7 8 9 | function getCode(obj: Person) { (obj as any).code(); } getCode(new Customer()) |
This is where the instanceOf
is becomes useful. We can use it to check the type and also infer the type in the block where InstanceOf
it is used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function getCode(obj: Person) { if (obj instanceof Customer) { obj.code(); } else if (obj instanceof SalesPerson) { obj.code(); } } getCode(new Customer()) //Customer Code getCode(new SalesPerson()) //SalesPerson Code |
Now, as you can see from the image below.
Outside the if block, the intellisense shows only one property name
, which is from the Person class.
Inside the (obj instanceOf customer)
block, the typescript correctly infers the type as Customer
, It shows the method Buy
But does not show the method Sell
While inside the (obj instanceOf SalesPerson
) block it infers the type as SalesPerson
. Here it shows the method Sell
and does not show Buy
.
Hence, the following BuySell
method correctly call the buy
& sell
methods and does not throw any errors.
1 2 3 4 5 6 7 8 9 10 11 12 13 | function BuySell(obj: Person) { if (obj instanceof Customer) { obj.buy(); } else if (obj instanceof SalesPerson) { obj.sell(); } } BuySell(new Customer()) BuySell(new SalesPerson()) |
In the following code, we just moved sell
method from the SalesPerson
to Customer
& vice versa. Now the compiler throws the error. For the error message you can see that outside the loop, Typescript infers the types a Person
. Inside the instanceof Customer
block it treats it as Customer
and inside the instanceof SalesPerson
it
1 2 3 4 5 6 7 8 9 10 11 12 13 | function BuySell(obj: Person) { obj.code(); //Property 'code' does not exist on type 'Person' if (obj instanceof Customer) { obj.sell(); //Property 'sell' does not exist on type 'Customer' } else if (obj instanceof SalesPerson) { obj.buy(); //Property 'buy' does not exist on type 'SalesPerson' } } |
Typeof vs Instanceof
typeof returns data type of the identifier as a string. instance returns true/false if a value is an instance of a class or a constructor function. It also takes its inheritance into account.
The typeof operator works mainly on primitive values (number, string, boolean, bigint, symbol & undefined) except for null. The typeof returns “function” for functions and for everything else, it returns “object”. It also returns “object” for null, which is a bug. On the other hand, instanceof is applicable only to objects and does not work on primitive values.
Instanceof does not work with Types
instanceof
will return true only if it matches the function from which it was constructed. It won’t tell you if a particular object is of a particular type.
For Example, in TypeScript, we can create a custom type using a type alias or interface. But these are specific to TypeScript and will be removed when code is compiled to JavaScript. Hene the type Person does not exist in JavaScript.
1 2 3 4 5 6 7 8 9 10 11 12 | type Person = { name: string; }; let p:Person = { name:"John"} p instanceof Person //Error //'Person' only refers to a type, but is being used as a value here. |