How to Check the Object Type on Runtime in TypeScript

Migel Hewage Nimesha Feb 02, 2024
  1. Main Types in TypeScript
  2. Check the Class Type on Runtime in TypeScript
  3. Check the Interface Type on Runtime in TypeScript
How to Check the Object Type on Runtime in TypeScript

This article discusses how to check the object type on runtime in TypeScript.

Main Types in TypeScript

TypeScript is a strongly typed language. Therefore, it checks for the types in compile time, which reduces runtime errors.

In TypeScript, we have several main types, as shown in the following.

  • Primitive types such as string, number, and boolean
  • Custom class types
  • Interface types
  • Union types
  • Type aliases

Check the Class Type on Runtime in TypeScript

TypeScript supports the class keyword from the EcmaScript 6. It can be used to write your code in an OOP way.

Let’s create the class Engineer.

class Engineer {
}

Let’s add a method since this class doesn’t contain any properties or behaviors.

class Engineer {
    visitSite(): void {
        console.log("This is the Engineer class");
    }
}

Let’s say we got another class, Doctor, as shown in the following.

class Doctor {
    visitWard(): void {
        console.log("This is the Doctor class");
    }
}

The Engineer and Doctor are two user-defined types. In some scenarios, we must check whether an existing object type belongs to the Engineer or Doctor class.

This is quite straightforward with the TypeScript instanceof operator.

Use the instanceof Operator to Check the Class Type

It checks whether the given object is an instance of a TypeScript class or a constructor. It considers the multi-level inheritance to check whether the relevant class appears at a different level.

If a matching class is found, it will return true; otherwise, it will output false.

Syntax:

my_object instanceof my_custom_class_type

Let’s use this operator to differentiate between Engineer and Doctor classes inside our TypeScript logic.

First, we will create a new checker function checkObjectType().

function checkObjectType(myObject) {
    if (myObject instanceof Engineer) {
        myObject.visitSite()
    }
    if (myObject instanceof Doctor) {
        myObject.visitWard()
    }
}

In the above checker function, we check the myObject’s class. Based on the result, we call the belonged class methods visitSite() or visitWard().

Let’s initiate objects from both the classes and pass the object to the checkObjectType method.

let engineerObject: Engineer = new Engineer;
let doctorObject: Doctor = new Doctor;
checkObjectType(engineerObject);
checkObjectType(doctorObject);

Output:

TypeScript Runtime Type Checking Output 1

As expected, TypeScript identifies the correct class for each object provided.

Check the Interface Type on Runtime in TypeScript

The instanceof can be used to check whether the given instance belongs to a class. But, this doesn’t work with TypeScript interface types or type aliases.

In runtime, all these interface types are gone. Hence, the usual JavaScript typeof operator will give the output as the object.

Let’s define two interfaces, Airplane and Car, as shown in the following.

interface Airplane {
    hasWings() {
        console.log("2 wings");
    }
}

interface Car {
    hasWheels() {
        console.log("4 wheels");
    }
}

Next, we will be creating a TypeScript user-defined type guard to check whether the given object belongs to the Airplane or Car type and narrow the object to a compatible type. Here, we should use type predicate as the return type.

Syntax of the type predicate:

my_parameter_name is custom_type

The my_parameter_name should be the current argument passed to the function. In this case, the custom_type will be the Airplane or Car.

Let’s define the two type guards:

function isAirplane(anyObject: any): anyObject is Airplane {
    return (anyObject as Airplane).hasWings() !=== undefined;
}

We check the shape of the object is equivalent to the interface shape by checking whether the hasWings() method is available to the passed object anyObject. Then, we return the type predicate that narrows the object to the Airplane type.

We can implement the isCar() function similarly.

function isCar(anyObject: any): anyObject is Car {
    return (anyObject as Car).hasWheels() !=== undefined;
}

Finally, we can implement the testType() function to test the code.

let car: Car = {wheels: 4};
let flight: Airplane = {wings: 2};

function testType(obj: any) {
  if (isAirplane(obj)) {
    // 'obj' is narrowed to type 'Airplane'
    console.log("Airplane wings: "+ obj.wings);
  }
  else if (isCar(obj)) {
    // 'obj' is narrowed to type 'Car'
     console.log("Car wheels: "+ obj.wheels);
  }
}

testType(car);
testType(flight);

Output:

TypeScript Runtime Type Checking Output 2

With the help of user-defined type guards, we can check the exact type for interfaces at runtime.

Migel Hewage Nimesha avatar Migel Hewage Nimesha avatar

Nimesha is a Full-stack Software Engineer for more than five years, he loves technology, as technology has the power to solve our many problems within just a minute. He have been contributing to various projects over the last 5+ years and working with almost all the so-called 03 tiers(DB, M-Tier, and Client). Recently, he has started working with DevOps technologies such as Azure administration, Kubernetes, Terraform automation, and Bash scripting as well.

Related Article - TypeScript Type