Defining generic types for subclasses inheriting from an abstract class containing type variables in TypeScript

Within my abstract class Base, I utilize a type variable <T> to define the type for the class. I have numerous derived classes that explicitly specify the type, like

class Derived extends Base<string> {...}

I aim to have a variable (or an array of variables) that can accept any of these derived classes, regardless of the <T>. Furthermore, I want to be able to use this variable to instantiate new instances of these Derived classes.

Below is my attempt at some code. However, I am stuck at this point.

TypeScript Playground link

abstract class Base<T> {
    abstract value: T;
}

class Derived extends Base<string> {
    value = 'Hello world!';
}

class SecondDerived extends Base<number> {
    value = 1234;
}

// This has type (typeof Derived | typeof SecondDerived)
let classes_A = [Derived, SecondDerived];

// This also works, but can become lengthy with multiple derived classes
let classes_B: (typeof Derived | typeof SecondDerived)[] = [];
classes_B.push(Derived);
classes_B.push(SecondDerived);

// The following scenarios do NOT work
let classes_C: Base<any>[] = [];
classes_C.push(Derived); // "typeof Derived is not assignable to type Base<any>"

let classes_D: Base<unknown>[] = [];
classes_D.push(Derived); // "typeof Derived is not assignable to type Base<unknown>"

let classes_E: Base<string>[] = [];
classes_E.push(Derived); // "typeof Derived is not assignable to type Base<string>"

let classes_F: (typeof Base)[] = [];
classes_F.push(Derived); // "typeof Derived is not assignable to typeof Base"

Answer №1

Here's a suggestion I have:

let classes: Array<new (...args: any) => Base<any>> = [];
classes.push(Derived); // works fine
classes.push(SecondDerived); // also works fine

The type of elements in the array should be "a constructor of any subtype of Base<T> for any T". To specify "a constructor of X", you can use a newable signature, like new () => X. This signature indicates the expected types and number of arguments the constructor requires. If you're indifferent to these details, you can use a rest argument of type any or any[], such as new (...args: any) => X.

Considering you're constructing a type that is any subtype of Base<T> for any T, and you likely don't need to track the specific subtype, Base<any> should suffice. (Unless you have a specific use case where this doesn't work, then please provide more details).

Hope this explanation helps; best of luck!

Playground link for code

Answer №2

To properly set up the constructor, you must specify the type:

type ConstructorBase = new () => Base<any>;

Once defined, you can use it to store a collection of Base constructors:

let constructorList: ConstructorBase [] = [];
constructorList.push(Derived);

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

The S3 signature verification failed while generating a signed URL on the server-side using Node.js

Trying to upload a video file to my bucket using a pre-signed URL in angular4. Instructions: let s3 = new AWS.S3(); s3.config.update({ accessKeyId: process.env.VIDEO_ACCESS_KEY, secretAccessKey: process.env.VIDEO_SECRET_KEY }) ...

How can I retrieve data during a double-click event in Kendo Grid using Angular?

How can I retrieve data on the doubleClick event in a Kendo Grid? I want to access the same object that is fetched during the selected event, which would be the dataitem at the selected index row. HTML: <kendo-grid #myGrid [data]="gridDat ...

The ngIf statement in the template isn't functioning properly after a refresh; instead, it is causing a redirection to the homepage

I've been developing with Angular 7, trying to display a <div> ... </div> based on multiple values that I declared as : Boolean = false; in the .ts file. These values are updated in ngOnInit, but for some reason, the page keeps redirecting ...

Is there a method for verifying the application signature in Ionic?

For the past 2 days, I've been on a quest to find information about app certificate validation libraries/functions in Ionic. After discovering SignatureCheck.java for Android (link: enter link description here), I wonder if there is a similar solution ...

Using GraphQL to set default values in data within a useEffect hook can lead to never

Here's the code snippet that I'm working with: const [localState, setLocalState] = useState<StateType[]>([]); const { data = { attribute: [] }, loading } = useQuery<DataType>(QUERY, { variables: { id: client && client.id ...

Ways to resolve the issue with the Argument of type 'Date[]' not matching the parameter type '(prevState: undefined) in React

I've encountered an issue while trying to construct my project. The error message reads as follows: Argument of type 'Date[]' is not assignable to parameter of type '(prevState: undefined) Here's the excerpt of the code in questio ...

"Unearthing a skeleton within the client component while the server action unfolds in next

One of the challenges I'm encountering involves a client component that initiates a server action. The server action returns a result, which triggers an update in the UI. Take a look at the code snippet provided below for reference export default func ...

Error message: "Declared app-routing module in Angular 2 is encountering routing declaration

Currently, I am immersing myself in learning Angular 2 through the official tutorial available at https://angular.io/docs/ts/latest/tutorial/toh-pt5.html. However, I have encountered an issue related to routing. The error message displayed states: Type Das ...

What advantages do interfaces as data types offer in Angular compared to using classes?

After watching a tutorial from my teacher, he showed us this code snippet: https://i.sstatic.net/MA3Z9.png He mentioned that the products array, defined as type any [], is not taking advantage of TypeScript's strongly typing. He suggested using an I ...

Ionic Vue is throwing an error indicating that a property is not found on the type '{ $route(currentRoute: any): void; }'

Currently, I am developing an Ionic WebApp using Vue and TypeScript. My current task involves retrieving the current id parsed by the route. To achieve this, I have been working on a watcher: export default { data() { return { ...

An error was detected in the card-module.d.ts file located in the node_modules folder within the @angular/material/card/typings directory

Currently, I am working on an angular project using Visual Studio Code as my text editor. When attempting to open the project with 'npm start', an error occurred. The specific error message is: ERROR in node_modules/@angular/material/card/typing ...

Generate a blueprint for a TypeScript interface

In my coding project, I've been noticing a pattern of redundancy when it comes to creating TypeScript interfaces as the code base expands. For example: interface IErrorResponse { code: number message: string } // Feature 1 type FEATURE_1_KEYS = ...

Incorporating a JavaScript file into Angular

I'm looking to incorporate a new feature from this library on GitHub into my Angular project, which will enhance my ChartJS graph. @ViewChild('myChart') myChart: ElementRef; myChartBis: Chart; .... .... const ctx = this.myChart.nativeEleme ...

Error message in Typescript with React: "The type 'ComponentClass<StyledComponentProps<{}>>' cannot be assigned to type 'typeof MyComponent'"

Currently experimenting with integrating the Material UI 1.0 (beta) @withStyles annotation into a React component. The documentation provides a JavaScript example (), however, it results in a compilation error when using Typescript. Despite the error, the ...

Guide on assigning a class to an array of JSON objects in TypeScript

If I have an array of JSON objects, how can I cast or assign the Report class to it? console.log('jsonBody ' + jsonBody); // Output: jsonBody [object Object],[object Object] console.log('jsonBody ' + JSON.stringify(jsonBody)); // Outpu ...

The dynamic concatenation of Tailwind classes is failing to have any effect, even though the full class name is being

I'm currently using Tailwind CSS within my Next.js project and I have a common method that dynamically returns the desired background color. However, despite adding the full class name, the background color is not displaying as expected. After reading ...

What is the best way to modify an object within a pure function in JavaScript?

Currently, I am exploring different strategies to ensure that a function remains pure while depending on object updates. Would creating a deep copy be the only solution? I understand that questions regarding object copying are quite common here. However, ...

Can ng-packagr create scripts that are compatible with running in a web browser like regular JavaScript?

Is it feasible to utilize ng-packagr to compile a library into a single script file that can be executed on a web browser by importing it as <script src="bundle.js"></script>? For instance, if I have a main.ts file that contains cons ...

Transferring data between pages in Next JS using App Route and Typescript

Seeking assistance to extract data from an array on one page and display it on another page. I am working with NextJs, Typescript, and AppRoute. Code in app/page.tsx: import Image from 'next/image' import Link from 'next/link' const l ...

What is causing the duplication of leaves when using this DFS implementation?

I created an algorithm to compare if two trees have the same leaves. https://i.sstatic.net/lpO2C.png Both trees display matching leaf numbers in the exact order, resulting in a true outcome. Below is the code that I formulated: function leafSimilar(root ...