Is there a way to retrieve the type of a generic class in JavaScript?

class Alpha {
  static construct<T extends typeof Alpha>(this: T): InstanceType<T> {
    const v = new Alpha();
    return v as InstanceType<T>;
  }
}

class Beta extends Alpha {}

const x = Alpha.construct(); // generates Alpha
const y = Beta.construct(); // yields Beta

Playground

I have now introduced generics to Alpha and Beta, resulting in this:

class Alpha<T = string> {
  static construct<T extends typeof Alpha>(this: T): InstanceType<T> {
    const v = new Alpha();
    return v as InstanceType<T>;
  }
}

class Beta<T = number> extends Alpha<T> {}

const x = Alpha.construct(); // generates Alpha<unknown>
const y = Beta.construct(); // yields Beta<unknown>

Playground

In this scenario, I anticipate receiving Alpha<string> and Beta<number>, but the default values for generics are not being applied while using InstanceType<T>.

Is there a way to include a generic and use a common method like .construct() above where both classes return instances with defaulted generics?

I also attempted T['prototype'] without success.

I was hoping to create a custom InstanceType, but it seems unattainable. Below is TypeScript's default definition for InstanceType, which may not access the generics.

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any

Answer №1

T pertains to a specific example of the category, and may vary for each instance. The method create within your class is marked as static, meaning it is not associated with any single instance of the class; thus, it does not inherit a generic T from the class.

The declaration <T = string> serves merely as a default setting. It does not constrain the potential values of

T</code in any manner. Consequently, when invoking a static method, your <code>T
essentially becomes unknown. Both Alpha and Beta can accommodate any value for
T</code, leaving you unaware of what <code>T
will be assigned to the instance generated through create() unless an explicit generic argument is provided.

Below shows the outcome when supplying an explicit generic parameter to create():

class Alpha<T = string> {
  // I've chosen a distinct name for this generic to indicate its independence from `T`
  static create<C = string>(): Alpha<C> {
    return new Alpha<C>();
  }
}

const a = Alpha.create<number>(); // yields Alpha<number>
const b = Alpha.create<[]>(); // yields Alpha<[]>
const c = Alpha.create(); // yields Alpha<string>

To extract the value of T from an Alpha, utilize this utility type:

type AlphaType<A> = A extends Alpha<infer T> ? T : never;

type A = AlphaType<typeof a> // displays number

Interactive Link

Answer №2

To create more constrained types, you can define T within Alpha and its subclasses:

class Alpha<T extends string = string> {
  static instantiate<T extends typeof Alpha>(this: T): InstanceType<T> {
    return new this() as InstanceType<T>;
  }
}

class Beta<T extends number = number> extends Alpha {}

const instanceA = Alpha.instantiate(); // results in Alpha<string>
const instanceB = Beta.instantiate(); // results in Beta<number>

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

find all the possible combinations of elements from multiple arrays

I have a set of N arrays that contain objects with the same keys. arr[ {values:val1,names:someName},   {values:val2,names:otherName}, ] arr2[   {values:valx,names:someNamex}, {values:valy,names:otherNamey}, ] My goal is to combine all possible c ...

AngularJS UI-Router in hybrid mode fails to recognize routes upon initial page load or reload

It appears that when using the @ui-router/angular-hybrid, routes registered within an ng2+ module are not being recognized during the initial load or reload. However, these same routes work fine when accessed by directly typing the URL. I have followed th ...

What is the best way to convert this into a distinct function using typescript?

Is there a way to create a single method in Protractor or Webdriver API that can get the browser width and height? const getWindowWidth = async () => { const size = await browser.manage().window().getSize(); return size.width; }; I need this metho ...

Angular 17 isn't notifying child component of signal changes

In the statistics module, I have a signal that specifies the type of charts to display and this signal is updated through a radio button group. The signal: typeSignal = signal<string>('OIA') The radio buttons for setting the : <div clas ...

What is the most efficient method for examining dependencies in Yarn 2 (berry)?

Is there a way to check for vulnerabilities in Yarn 2 dependencies? In Yarn 1.x, you could run yarn audit, similar to npm audit. However, this command is not available in Yarn 2. According to this issue on the Yarn berry Github, it may not be implemented ( ...

Discover the Prisma findMany method for implementing tanstack react table functionality

I'm looking to build a table (using tanstack table) populated with data fetched from Prisma.findMany. Let's suppose I have a User model: model User { id Int @id @default(autoincrement()) name String age String email String } Now, in my p ...

After updating from angular4 to angular 5, the npm test is failing with the error message "TypeScript compilation cannot find test.ts file"

After upgrading my app from Angular4 to Angular 5 using the steps provided on https://update.angular.io/, I encountered an issue. While I can successfully run ng-serve and ng build without any problems, the npm test command for ng test is failing with the ...

Extending the Object prototype within an ES6 module can lead to errors such as "Property not found on type 'Object'."

There are two modules in my project - mod1.ts and mod2.ts. //mod1.ts import {Test} from "./mod2"; //LINE X interface Object { GetFooAsString(): string; } Object.prototype.GetFooAsString = function () { return this.GetFoo().toString(); } //mod2. ...

Using Typescript to import a module and export a sub function

I am currently using mocha for testing a function, but I have encountered an error while running the test file. The structure of my files is organized as follows: server |-test | |-customer.test.ts |-customer.js Here is the content of the customer.js fi ...

ES6 Update: Manipulating Nested Arrays with JavaScript

I have the following list of items: [ { idItem: "1", name: "apple", itemLikes: [{ id: "1", idItem: "1" }] } ] My goal is to simply add a new object to the itemLikes array. Here is my ...

There is an issue with the type candidate in the Notion API, resulting in

In this instance, the troublesome code causing issues is displayed below: import {Client, LogLevel} from "@notionhq/client"; const notion = new Client({ auth: process.env.NOTION_TOKEN, logLevel: process.env.NODE_ENV !== 'product ...

The noUnusedLocal rule in the Typescript tsconfig is not being followed as expected

I am currently working on a project that utilizes typescript 3.6.3. Within my main directory, I have a tsconfig.json file with the setting noUnusedLocals: true: { "compilerOptions": { "noUnusedLocals": true, "noUnusedParameters": true, }, ...

Error: No default Firebase App named '[DEFAULT]' exists. Please remember to call Firebase App.initializeApp() to create the app (app/no-app). This issue is located at the app

Currently, I am in the process of learning how to integrate Firebase Functions into an Ionic + Angular project. My goal is to develop a custom function that retrieves all games from a collection and returns an array sorted by the "count" attribute. Initia ...

Silence in Angular NGRX Effects

I am currently utilizing ngrx Effects to send a http call to my server, but for some reason the effect is not triggered. My goal is to initiate the http call when the component loads. I have tried using store.dispatch in ngOnInit, however, nothing seems to ...

Change the spread operator in JavaScript to TypeScript functions

I'm struggling to convert a piece of code from Javascript to Typescript. The main issue lies in converting the spread operator. function calculateCombinations(first, next, ...rest) { if (rest.length) { next = calculateCombinations(next, ...res ...

Creating Angular components in *ngFor loop

I have set up multiple radio button groups by dynamically populating options using ngFor within a ngFor loop. categories:string[] = [category_1, ..., category_n]; options:string[] = [option_1, ..., option_n]; <fluent-radio-group *ngFor='let ca ...

Purge React Query Data By ID

Identify the Issue: I'm facing a challenge with invalidating my GET query to fetch a single user. I have two query keys in my request, fetch-user and id. This poses an issue when updating the user's information using a PATCH request, as the cach ...

What could be the reason for the Angular2 Component property not appearing on my webpage?

Here is the code snippet I am working with: import {Component} from "@angular/core"; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>{{secondTitle}}</h2> <main-page></ma ...

What could be the reason for the react hook form failing to capture the data upon submission?

I am struggling to access the props' value after clicking the button, as it keeps returning undefined. My goal is to display the years of service and profession details based on the user's selection. return ( <form onSubmit={handleSubmit(o ...

Using TypeScript to define values with the placeholder "%s" while inputting an object as a parameter

One common way to decorate strings is by using placeholders: let name = "Bob"; console.log("Hello, %s.", name) // => Outputs: "Hello, Bob." I'm curious if there's a way to access specific values within an object being passed in without specif ...