Creating asynchronous JavaScript constructors using a static method called "create" presents challenges when dealing with TypeScript types

I've been diving into the world of asynchronous constructors and have successfully implemented them in JavaScript.

However, I'm facing a challenge with TypeScript types. Here's how it should ideally work:

const a: AnyClass = await AnyClass.create();

While this setup works perfectly in JavaScript, the TypeScript types are currently missing.

Let's consider the example of a similar class named DbConnection:

class DbConnection extends AsyncConstructor<[serverId: number, url: string]> {
    #serverId: number;
    #connection: Connection;

    protected constructor(serverId: number, url: string) {
        super(serverId, url);
        this.#serverId = serverId;
    }

    protected override async constructorAsync(serverId: number, url: string): Promise<void> {
        this.#connection = await DB.connect(url);
    }
}

The foundation class is as follows:

class AsyncConstructor<CtorParams extends any[]> {
    protected constructor(...args: CtorParams) {}

    protected async constructorAsync(...args: CtorParams): Promise<void> {
        return Promise.resolve();
    }

    // =-->>> MISSING TYPES FOR THE NEXT METHOD: <<<--=
    static async create(...args: CtorParams) {
        const res = new this(...args);
        await res.constructorAsync(...args);
        return res;
    }
}

My question is, what type should be specified for the return value of the create method?

Answer №1

It is currently not possible in 2024 due to the limitations of TypeScript (specifically version 5.3 or lower).


  • According to @KernelDeimos, there is an unresolved issue in the TypeScript repository regarding polymorphic "this" for static members - Issue #5863
  • Additionally, as mentioned by @jonrsharpe, a similar problem has been discussed here - Using `this` as a generic type on a static method

The only potential partial solution at present is:

class DbConnection  {
    #serverId: number;
    #connection: Connection;

    static async create(serverId: number, url: string): Promise<DbConnection> {
        const connection = await DB.connect(url);
        const res = new DbConnection(serverId, url, connection);        
        return res;
    }

    protected constructor(serverId: number, connection: Connection) {        
        this.#serverId = serverId;
        this.#connection = connection;
    }
}

However, this approach comes with its drawbacks:

  • Inability to enforce consistent implementation across classes
  • Resulting in each class having its own unique name and creation process
  • Potential complications during inheritance within complex class structures, particularly in large codebases

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

Options for importing TypeScript in WebStorm

Using WebStorm for auto-importing TypeScript classes has been a great help to tidy up my code and make it more organized. However, I have noticed that the imports are always formatted in a single line like this: import { Component, EventEmitter, Input, O ...

Creating a Webgrid in MVC and integrating it with a custom class in AngularJS

Hey there, I'm a beginner when it comes to AngularJS and I'm looking to bind the webgrid within the method of AngularJS. $scope.SaveDetails = function () { debugger; var UserID = '@Session["ID"]'; ...

Activate Gulp watcher to execute functions for individual files

I have developed a specific function that I need to execute only on the file that has been changed with gulp 4.0 watcher. For example, the current task setup looks like this: gulp.watch([ paths.sourceFolder + "/**/*.js", paths.sourceFolder + "/**/ ...

What is the best way to solve the problem of Chrome auto-complete overlapping with labels in Vuetify?

When attempting to make a login form using outlined text fields in Vutify, there is an issue with Chrome autocomplete overlapping the labels. <v-text-field v-model="email" label="e-mail" name="email" outlined prep ...

What could be the reason for the HTML canvas not displaying anything after a new element is added?

How come the HTML canvas stops showing anything after adding a new element? Here is my HTML canvas, which works perfectly fine until I add a new element to the DOM: <canvas class="id-canvas", width="1025", height="600"> ...

The Express.js server encounters a 404 error, causing it to panic and throw an exception before I can even address the issue

(Just so you know, I'm utilizing the Blizzard.js npm package in combination with Express.) I am currently working on a web application that allows users to search for statistics of specific video game characters (profiles created by players). Given t ...

Why does TypeScript struggle to accurately deduce the return type when provided with certain parameter values?

I have a function that uses a switch case to return different results depending on the input. The function, called "getTimeAgo," takes in two parameters: "date" (which can be either a Date object or a string) and "mode" (which can only be either "days" or ...

Generating personalized MongoDB collections for individual users - A step-by-step guide

My query is more about the procedure rather than a specific coding issue. I am working on a node application and using DHTMLX calendar. What I aim for is to have each user with their own set of events on their individual calendar. Currently, the implement ...

Adjust variable values when the window is resized

I've been working on getting some variable values to update when the window is resized. After researching, I learned that it's recommended to declare the variables outside of the .resize function scope and then try to change their values within ...

The React Callservice script is failing to fetch the required data from the Node.js script responsible for making the API call

Recently, I decided to create a basic webpage using React.js to display data fetched from an API. Although the project is intended to be straightforward, my lack of recent development experience has led to a perplexing issue that I can't seem to resol ...

The asynchronous ajax function fails to work properly when setInterval is activated

My issue is that only the initial execution of the updateProgress function happens while waiting for the completion of syncDNS. All subsequent calls made via setInterval remain on hold until syncDNS finishes. Can anyone explain why this is happening? $( ...

What is the best way to utilize the features of component A within component B when they exist as separate entities

Component A has all the necessary functionalities, and I want to use it in Component B. The code for ComponentA.ts is extensive, but it's not written in a service. How can I utilize the logic from Component A without using a service, considering both ...

Angular utilizing external parameter for Ajax requests

As a newcomer to Angular, I am eager to upgrade some old jQuery code with AngularJS. The task at hand is to extract a string from a span element, split it into two separate strings, and then use these as parameters in a GET request. I am dedicated to lea ...

The Material UI Elements are not displaying properly as expected. Instead of seeing the MUI elements, a tan box is appearing. What steps can I take to resolve this

I'm currently using Material UI to build a basic header, footer, and profile page. However, whenever I attempt to display any type of element (such as Menu, Appbar, Toolbar, IconButton, Tab, Tabs, etc.), the page only shows a tan box instead of the a ...

Do you know the term for when JavaScript is utilized to display specific sections of a png image?

Imagine you have an image file in the format of a PNG which includes various icons intended for use on a website. How can JavaScript be utilized to choose and showcase a specific icon from that image? It's a technique I've observed in practice, b ...

What is the best way to generate a "JSON diff" that can be displayed in the JavaScript console?

When working on my Angular project, I frequently encounter the need to compare JSONs in my Karma/Jasmine tests. It would be incredibly useful to have a console output showing what has been added and removed when comparing two structures. For example, ident ...

JS will reach its stopping point at the specified style.zIndex

I am currently in the process of setting up button elements. I have two scripts that correspond to different types of buttons - one script runs a simple collapse menu, while the other executes a more complex collapse by shifting depths and sliding one div ...

Fetch a document from a NodeJS Server utilizing Express

Is there a way to download a file from my server to my machine by accessing a page on a nodeJS server? I am currently using ExpressJS and I have attempted the following: app.get('/download', function(req, res){ var file = fs.readFileSync(__d ...

In my Node.js/Express.js application, I have a directory that holds various images. Whenever I attempt to view these images via their URL, I encounter a 404 error message

In my Node.js/Express js project, I have the following folder structure: root ----bin ----controllers ----middleware ----models ----node_modules ----public --------images ------------test.png ----routes ----views I am currently trying to determine the cor ...

What are some techniques for animating SVG images?

Looking to bring some life to an SVG using the jQuery "animate" function. The plan is to incorporate rotation or scaling effects. My initial attempt with this simple code hasn't yielded the desired results: $("#svg").animate({ transform: "sc ...