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

Incorporating the non-typescript npm package "pondjs" into Meteor applications using typescript files

Implementing the Pondjs library into my project seemed straightforward at first: meteor npm install --save pondjs However, I'm encountering difficulties when trying to integrate it with my Typescript files. The documentation suggests: In order ...

You cannot invoke this expression while destructuring an array of React hooks in TypeScript

Within my React TypeScript component, I have several fields that check a specific condition. If the condition is not met, the corresponding field error is set to true in order to be reflected in the component's DOM and prevent submission. However, whe ...

Managing the display of numerous ngFor components

If you're interested in learning more about the features I will include, here's a brief overview. I plan to have a project section with cards displayed for each project, all populated from a JSON file. When users click on a card on the website, a ...

When using Styled Components with TypeScript, you may encounter the error message "No overload matches

Recently, I've delved into Style Components in my journey to create a weather app using React Native. In the past, I would typically resort to CSS modules for styling, but it appears that this approach is not feasible for mobile development. Below is ...

Creating Dynamic ion-card Elements in Typescript by Programmatically Changing Values

Currently, I am working on a basic app that retrieves posts from the server and displays them as cards on the screen. At this early stage, one of my main challenges is figuring out how to dynamically add ion-card elements with changing content and headers ...

Unable to locate any static exports within the TypeScript library bundle

In my file Style.ts, I have a class called Style: export class Style { ... } The Style class consists of properties, methods, and a constructor, along with import statements for other class dependencies. It is being used by other classes through the ...

Fixing the "Module not found" error in an Angular library using npm link

I'm currently working on creating an Angular wrapper for a Javascript library, but I've encountered a "Module not found" error. The Javascript library is still in development and has not been published to NPM yet. To work around this issue, I hav ...

Managing a scenario with a union type where the value can be retrieved from one of two different functions

There are two similar methods that I want to refactor to eliminate redundant code. The first function returns a single element, while the second function returns multiple elements: //returns a single element const getByDataTest = ( container: HTMLElement ...

Utilizing Typescript for Axios Response

Incorporating Typescript into my project, I encountered a tedious issue while making an API call using axios. The problem lies within handling nested data properly. Despite my belief that I have correctly typed everything, I persistently face a Typescript ...

When utilizing ng2-bootstrap, there is no directive that is defined with the "exportAs" attribute set to "bs-modal"

I found a tutorial that I am trying to emulate from this website However, when I insert the template into my HTML file <div class="modal fade" bsModal #staticModal="bs-modal" [config]="{backdrop: 'static'}" tabindex="-1" role="dialog" ...

D3-cloud creates a beautiful mesh of overlapping words

I am encountering an issue while trying to create a keyword cloud using d3 and d3-cloud. The problem I am facing is that the words in the cloud are overlapping, and I cannot figure out the exact reason behind it. I suspect it might be related to the fontSi ...

Effortlessly collapsing cards using Angular 2 and Bootstrap

Recently delving into Angular 2 and Bootstrap 4, I set up an about page using the card class from Bootstrap. Clicking on a card causes it to expand, and clicking again collapses it. Now, I want to enhance this by ensuring that only one card is open at a ti ...

The error message "tsc not found after docker image build" appeared on the

My goal is to deploy this program on local host. When I manually run "npm run build-tsc," it works successfully. However, I would like Docker to automatically run this command when building the image. Unfortunately, I receive an error saying that tsc is no ...

Having trouble resolving modules with Angular 2 and ASP.NET 5 (unable to locate angular2/core)?

I am diving into a fresh ASP.NET5/MVC6 project and facing some challenges along the way. Struggle 1 When I opt for classic as the moduleResolution in my tsconfig.json, I encounter an error stating: Cannot locate module 'angular2/core' Strugg ...

I encountered a permission denied error while attempting to execute the command npm install -g tsc

My main objective is to convert TypeScript code to JavaScript. However, when I attempted to install the TypeScript compiler globally using 'npm install -g tsc', I encountered the following error: npm ERR! Error: EACCES: permission denied, rename ...

Collaborate on Typescript Interfaces within a Firebase development environment

I've been developing a Firebase project using Angular for the frontend, and incorporating the @angular/fire library. Within this project, I have created multiple interfaces that utilize firebase and firestore types. For example: export interface ...

The introduction of an underscore alters the accessibility of a variable

When working in Angular, I encountered a scenario where I have two files. In the first file, I declared: private _test: BehaviorSubject<any> = new BehaviorSubject({}); And in the second file, I have the following code: test$: Observable<Object& ...

It's conceivable that the item is 'null'

I am encountering Typescript errors in my code that are related to parameters I am receiving from a previous screen. This is similar to the example shown in the React Navigation documentation found at https://reactnavigation.org/docs/params/. interface Pix ...

"Ionic Calendar 2 - The ultimate tool for organizing your

I am using a calendar in my Ionic app that retrieves events from a database through an API. var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://portalemme2.com.br/SaoJoseAPI/agenda', true); this.http.get('http://portalemme2.c ...

Understanding TypeScript typing when passing arguments to the Object.defineProperty function

After reviewing all the suggested answers, including: in Typescript, can Object.prototype function return Sub type instance? I still couldn't find a solution, so I'm reaching out with a new question. My goal is to replicate Infix notation in J ...