What is the best way to define a general class within the constructor of another class in TypeScript?

Is there a way to inject a subclass into a class during its constructor using TypeScript?

I've tried to demonstrate my idea with some pseudo-code here:

type GenericConstructor<T> = { new (): T; }

class MyClass {
  constructor(
    SubClass: GenericConstructor
  ) {
     this.subclass = new SubClass();
  }
}

class MySubClass1 {}

class MySubClass2 {}

const withSubClass1 = new MyClass(MySubClass1);
const withSubClass2 = new MyClass(MySubClass2);

The issue is that TypeScript doesn't seem to allow specifying a generic parameter for a constructor. I think I might be missing something here.

My goal is to have a class (MyClass) that can accept a generic child class which meets specific interface requirements. Maybe defining an interface would be the right approach, but I'm not sure how to go about it.

Thank you in advance for your assistance!

Answer №1

It's not possible to declare a generic `constructor` method because it could conflict with the class itself being generic. For example:

class Foo<T> { constructor<U>() { } } // error, but imagine no error

If this were allowed, when calling `new Foo<X>()`, it would be unclear if `X` refers to `T`, `U`, neither, or both. There are workarounds for this situation, but in your case, they may not be necessary.


Instead, if you want `withSubClass1` to have its `subclass` property remember that it is of type `SubClass1`, and similarly for `withSubClass2`, then `MyClass` should be generic in the type of the `subclass` property. Let the compiler infer this type from the constructor parameter:

class MyClass<T> {
  subclass: T;
  constructor(subclassCtor: new () => T) {
    this.subclass = new subclassCtor();
  }
}

When constructing instances, you get:

const withSubClass1 = new MyClass(MySubClass1);
// const withSubClass1: MyClass<MySubClass1>

const withSubClass2 = new MyClass(MySubClass2);
// const withSubClass2: MyClass<MySubClass2>

Assuming `MySubClass1` and `MySubClass2` have distinct structures:

class MySubClass1 { a = "" }
class MySubClass2 { b = "" }

Instances of `MyClass` will have that structure in their `subclass` property:

withSubClass1.subclass.a.toUpperCase(); // okay
withSubClass2.subclass.b.toLowerCase(); // okay

I hope this explanation helps and wish you good luck!

Link to Playground code

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

Using GitHub Actions to automatically publish a Typescript Package: A Step-by-Step Guide

Utilizing GitHub actions, I have automated the process of publishing my npm package whenever I push code to the master branch. However, I am facing an issue with my .gitignore file where I have excluded the /dist/ folder. As a result, when the code is push ...

What is the best way to set up an endpoint in Angular for image uploading?

Using the Kolkov Angular editor in my Angular application, I have successfully created a rich text editor. Currently, I am looking to upload images from the editor to the server. I already have a function in place that takes a file as an argument and send ...

Bidirectional data binding in Angular 2 allows for communication between parent components and directives

Update: Experimenting with Angular2 Beta, I am working on incorporating an "editor" component template that includes a directive wrapping the Ace editor. In this scenario, the "editor" component acts as the parent of the Ace wrapper directive, and my goal ...

Clicking on a component in Nuxt will trigger it to open

Is there a way to trigger a modal window to open when a button is clicked without storing the modal window in the header? file header: <template> <section class="header"> <div class="header-container"> ...

The updated values in an Angular application may not always be accurately represented by interpolated values

The values of the elements in the dropzone1 array only show the initial top and left values, not the latest ones. Within the draw() function, I add the top and left values to the topLeft array and then push it to the dropzone1 array inside the move() func ...

Error: Failed to load chunk 552 due to chunk loading issue

Currently in the process of migrating Angular 12 to version 13. The migration itself was successful, however, upon running the project in the browser post a successful build, the application fails to display. On checking the console, I encountered the foll ...

Enforce boundaries by constraining the marker within a specified polygon on a leaflet map

Currently, I am utilizing a leaflet map to track the user's location. The map includes a marker for the user and a polygon shape. My goal is to ensure that the user marker always stays within the boundaries of the defined polygon. In case the user mov ...

"From time to time, reimport React when saving to ensure all necessary imports are

When working with TypeScript in *.tsx files, particularly when copying code around, I frequently encounter the issue of an additional import line being added. This can be seen below: import React from "react"; // ? On Save "editor ...

What benefits does Observable provide compared to a standard Array?

In my experience with Angular, I have utilized Observables in the state layer to manage and distribute app data across different components. I believed that by using observables, the data would automatically update in the template whenever it changed, elim ...

Communicating with an ASP.NET Controller using Angular2: A Step-by-Step Guide

I am working with a controller that includes a Create action. The main purpose of this action is to receive a name and data from a file form, and then return a list of files using the IndexViewModel. public class HomeController : Controller { static L ...

How can I apply concatMap in Angular?

Can you please guide me on how to effectively utilize concatMap with getPrices() and getDetails()? export class HistoricalPricesComponent implements OnInit, OnDestroy { private unsubscribe$ = new Subject < void > (); infoTitle ...

Is there a way to prompt TypeScript to report an error when a mapped key is missing?

Here is my current code snippet: type TransferType = 'INTERNAL' | 'WITHDRAWAL' | 'DEPOSIT' type TransferEvents = Record<TransferType, Record<string, TypeFoo | TypeBar>> export interface EventsTooltip extends Tran ...

A mistake occurred: The function this.http.get(...) is not supported with the method map within BookService.push

Below is my code for the books service: import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; //impo ...

Navigating Through Angular Components

I have a layout with 3 components arranged like this: <app-header></app-header> <app-body></app-body> <app-footer></app-footer> However, I want to change the positioning of the footer and body as shown below: <app-he ...

What is the process for including a unique attribute for child elements within a React component using TypeScript?

I have a component that creates a Table of Contents (TOC) and List for the child elements. These children can be any JSX.Element. Here is an example... <SectionScrollList> <View key="first"/> <View key="second"/> ...

Obtain the file path relative to the project directory from a Typescript module that has been compiled to JavaScript

My directory structure is as follows: - project |- build |- src |- index.ts |- file.txt The typescript code is compiled to the build directory and executed from there. I am seeking a dependable method to access file.txt from the compiled module without ...

Enhance the readability of your Angular/Ionic applications with proper hyphenation

In my Ionic 3 app, I am using an ion-grid. Some words do not fit within the columns and are cut off, continuing on the next row without any hyphens added for proper grammar context. See image https://i.stack.imgur.com/3Q9FX.png. This layout appears quite ...

How can you incorporate TypeScript's dictionary type within a Mongoose schema?

When using TypeScript, the dictionary type format is: { [key: string]: string; } However, when I try to define a custom schema in mongoose, it doesn't work as expected. const users = new Schema({ [key: string]: String, }); I also attempted t ...

The response from the Http GET request in the Angular web service app was delayed

I am currently working with Angular CLI version 8.3.2 and Node version 10.16.3 on win32 x64. My project involves integrating an Angular frontend with a .NET backend. The frontend communicates with the backend API to retrieve a list of messages using an HTT ...

TypeScript is encountering difficulty locating a node module containing the index.d.ts file

When attempting to utilize EventEmitter3, I am using the following syntax: import EventEmitter from 'eventemitter3' The module is installed in the ./node_modules directory. It contains an index.d.ts file, so it should be recognized by Typescrip ...