Is it possible to utilize instanceof to verify whether a certain variable is of a class constructor type in TypeScript?

I am currently facing an issue with a function that takes a constructor as a parameter and creates an instance based on that constructor. When attempting to check the type of the constructor, I encountered an error.

Below are some snippets of code that I have experimented with:

First attempt:

function hello(arg: Function) {
  if(arg instanceof typeof MyClass) { // .. constructor(a: number) ..
    return new arg(123)
  } else if(arg instanceof typeof MyClass2) { // .. constructor(a: string) ..
    return new arg('abc')
  } else return arg(true)
}

This resulted in the following error:

The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type. ts(2359)

Second attempt:

// ...
if (arg.prototype instanceof Component) {
  const hi = new arg(123)
  // ...
}

However, this also led to an error:

Cannot use 'new' with an expression whose type lacks a call or construct signature. ts(2351)

My goal is to validate the type of certain constructors like so:

hello(MyClass) // new MyClass(123)
hello(MyClass2) // new MyClass2('abc')

Answer №1

Consider the classes given below:

class SampleClass {
  constructor(public x: number) {}
}

class AnotherSampleClass {
  constructor(public y: string) {}
}

A factory function can be created in the following way:

function createInstance<T extends new (...args: any[]) => any>(arg: T): InstanceType<T> {
   if (arg instanceof SampleClass) {
      // .. constructor(x: number) ..
      return new arg(123);
   } else if (arg instanceof AnotherSampleClass) {
      // .. constructor(y: string) ..
      return new arg("abc");
   } else return new arg(true);
}

InstanceType is a useful builtin utility type.


Usage example:

const obj = createInstance(SampleClass); // type = SampleClass

Answer №2

When working with Typescript, constructor functions are an integral part of classes. The Typescript compiler will generate JavaScript "constructor" functions for ES5 or earlier versions, and for more recent ECMAScript versions, the output JavaScript will maintain the use of the class keyword.

This code snippet draws inspiration from the Typescript handbook section on instanceof type guards.

Instead of creating a function that takes a constructor function as a parameter, the function instantiateClass is designed to receive a Typescript class, which it then instantiates and returns based on the runtime type.

An Example of a Typescript Function That Accepts a Class for Instantiation

interface Padder {
    getPaddingString(): string
}

class SpaceRepeatingPadder implements Padder {
    constructor(private numSpaces: number) { }
    getPaddingString() {
        return Array(this.numSpaces + 1).join(" ");
    }
}

class StringPadder implements Padder {
    constructor(private value: string) { }
    getPaddingString() {
        return this.value;
    }
}

function instantiateClass(myClass: new (...args: any[]) => any): Padder {
    if (myClass instanceof SpaceRepeatingPadder) {
        return new myClass(2 /* numSpaces */);
    } else if (myClass instanceof StringPadder) {
        return new myClass('*' /* value */);
    } else {
        return new myClass()
    }
}

let padder = instantiateClass(SpaceRepeatingPadder);
if (padder instanceof SpaceRepeatingPadder) {
    console.log("type narrowed to 'SpaceRepeatingPadder'")
}
if (padder instanceof StringPadder) {
    console.log("type narrowed to 'StringPadder'")
}

padder = instantiateClass(StringPadder);
if (padder instanceof SpaceRepeatingPadder) {
    console.log("type narrowed to 'SpaceRepeatingPadder'")
}
if (padder instanceof StringPadder) {
    console.log("type narrowed to 'StringPadder'")
}

Console Output

type narrowed to 'SpaceRepeatingPadder'
type narrowed to 'StringPadder'

Check out the example in the TypeScript Playground

In the Playground, go to Options and experiment by changing the target version of ECMAScript.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you provide instructions on executing package dependencies using yarn in the command line? For example, is there a command similar to npx tsc init for initializing a npm

When utilizing yarn, the node_modules folder is not present. Instead, dependencies are stored in a .yarn/cache folder. I attempted to use yarn dlx tsc init and npx tsc init, but they did not achieve the desired result. There are various development depend ...

Unable to utilize Stats.js with @angular/cli version 1.4.4

Attempting to utilize @types/stats with @angular/cli following the guidance at https://github.com/angular/angular-cli/wiki/stories-third-party-lib. However, encountering a tslint error when trying to import * as STATS from 'stats.js'. [ts] Modul ...

Guide to correcting the file path of an external css within the public directory on Express framework

I am facing an issue with loading external CSS files and need some help to fix the path. Despite multiple attempts, I have been unsuccessful so far. Below is my category structure: https://i.stack.imgur.com/sLTcN.png Within the header.ejs file, this is h ...

What could be causing the empty object return from the Async function in my Typescript code on Next JS?

Encountering issues with an async function. In the ../lib folder, I have a class for handling data from an API website. However, when attempting to load the API data within an async function, I encounter difficulties. The async function does not return a ...

Unexplained Reference Error in Next.js Typescript: Variable Accessed before Initialization

I am currently working on an admin website and encountered the error Block-scoped variable used before its declaration.. I will provide details using images and code. This is my first time seeking help on StackOverflow. Error Message: Block-scoped variab ...

Here is an example showcasing how to use Angular 2 to make an

How can I correctly retrieve json data from an http get request in Angular 2? Currently, I am working on testing some local data with a mocked endpoint. Although I am able to see the result in the http.get() method, I am facing issues when trying to assign ...

How to extract key-value pairs from an object in a TypeScript API request

I am trying to extract the data '"Cursed Body": "100.000%"' from this API response using TypeScript in order to display it on an HTML page. Can anyone help me figure out how to do this? API Response { "tier": &q ...

Retrieving Data in Typescript Async Function: Ensuring Data is Returned Once All Code is Executed

I need help with waiting for data to be retrieved before returning it. The code below fetches data from indexedDB and sends it back to a component. I understand that observables or promises can accomplish this, but I am struggling with how to implement t ...

Build a stopwatch that malfunctions and goes haywire

I am currently using a stopwatch that functions well, but I have encountered an issue with the timer. After 60 seconds, I need the timer to reset to zero seconds and advance to one minute. Similarly, for every 60 seconds that pass, the minutes should chang ...

Using TypeScript - Implementing Reduce function with a return type containing optional fields

I am facing challenges in satisfying the TypeScript compiler with my code. I define a type that includes only optional fields, for example: interface UserData { email?: string; phone?: string; //... } and I have a reduction function that transforms ...

Double invocation of ActivatedRoute.params.subscribe method observed

To extract URL parameters, I'm utilizing the ngOnInit() method where I've implemented the following snippet: this.activatedRoute.queryParams.subscribe(params => { console.log(params); // actual implementation here }); Yet, upon initi ...

Issue encountered while trying to iterate through an observable: Object does not have the capability to utilize the 'forEach' property or method

I am currently following the pattern outlined in the hero.service.ts file, which can be found at this link: https://angular.io/docs/ts/latest/guide/server-communication.html The Observable documentation I referenced is available here: When examining my c ...

Retrieving the chosen option from a personalized drop-down element

I have been working on a project using Angular 2, where I created a dropdown component with the following code: @Component({ selector: 'dropdown', template: ` <div class="row" > <div class="col-sm-3"> ...

What is the best way to handle various sections with changing structures within a complex form using react-hook-form?

I am working on a complex form that has sections A, B, and C, each of which can be in shape A1 or A2, B1 or B2, C1, or C2. Users are required to fill out settings based on whether the section is set to "advanced" or "basic". I want users to submit the enti ...

Setting up Webpack for Node applications

My current challenge involves configuring Webpack for a node app that already exists. I am encountering various issues and struggling to find solutions or even know where to begin. Situation The project's folder structure is as follows: +---app +-- ...

Versatile Typescript options

Is it possible to enforce a value to be within a list using TypeScript with enums? Can this be achieved with TypeScript type definitions? enum Friend { JOHN, SALLY, PAUL, } type MyFriends = { friends: Friend[], bestFriend: <> //How ca ...

Bringing Typescript classes into React-scripts does not act as a constructor

I am currently working on integrating a Typescript file into my existing app using Yarn and React-scripts. Encountered error: Module not found, unable to resolve './DiamondNodeModel' import {DiamondNodeModel} from './DiamondNodeModel&ap ...

Changing an element within an item stored in Ionic Storage

Hello, I am currently attempting to update a specific part of an object stored in Ionic storage. The current data in the Storage looks like this: key : object value : {a: "1", b: "2", c: "3"} To modify one of the values to 10, I created the following fu ...

Issues with the ngModel data binding functionality

I'm currently working on the Tour of Heroes project and facing an issue with ngModel. It seems like hero.name is not being updated, or maybe it's just not reflecting in the view. Despite typing into the input field, the displayed name remains as ...

Tips for RETRIEVING a particular cookie value in Angular version 14

"I've integrated the ngx-cookie-service library in my Angular project, but I'm experiencing an issue where two different cookies are being retrieved upon login even though the session id is already set in the backend. How can I ensure that m ...