Pattern for asynchronously constructing objects with a generic parent class

Is there a way to modify the constructWhenReady method so that it returns only Child, without any changes to the 'calling' code or the Child class? I am looking for a solution to implementing an async constructor, but existing solutions are not compatible when the Parent class is generic.

class Parent<PropType extends any> {
    static isReadyForConstruction = new Promise(r => setTimeout(r, 1000));

    static async constructWhenReady<T extends typeof Parent>(this: T): Promise<InstanceType<T>> {
        await this.isReadyForConstruction;
        return new this() as InstanceType<T>;
    }

    get something(): PropType {
       // ...
    }
}

class Child extends Parent<{ a: 'b' }> { }

// Error: '{ a: "b"; }' is assignable to the constraint of type 
// 'PropType', but 'PropType' could be instantiated with a different 
// subtype of constraint 'unknown'.
const x = await Child.constructWhenReady(); 


Reasoning: The goal is to ensure that less experienced developers writing Child classes and using them have clean code (especially in test automation). One simple approach would be to require everyone to use await new Child().init(), but it would be preferable to catch errors during coding rather than at runtime.

Answer №1

The method constructWhenReady is designed to work regardless of the type that the generic argument PropType is instantiated with. This should be explicitly stated:

class Parent<PropType> {
    static isReadyForConstruction = new Promise(r => setTimeout(r, 1000));

    static async constructWhenReady<T extends typeof Parent<unknown>>(this: T): Promise<InstanceType<T>> {
    //                                                     ^^^^^^^^^
        await this.isReadyForConstruction;
        return new this() as InstanceType<T>;
    }

    get something(): PropType {
       // ...
    }
}

It's worth noting that you can eliminate the need for the as InstanceType<T> cast by using the following approach:

static async constructWhenReady<T extends Parent<unknown>>(this: {new(): T; isReadyForConstruction: Promise<unknown>}): Promise<T> {
    await this.isReadyForConstruction;
    return new this();
}

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

Angular 8 delivers an observable as a result following a series of asynchronous requests

I am working on a simple function that executes 3 asynchronous functions in sequence: fetchData() { this.fetchUsers('2') .pipe( flatMap((data: any) => { return this.fetchPosts(data.id); }), fl ...

Is it possible to assign a property value to an object based on the type of another property?

In this illustrative example: enum Methods { X = 'X', Y = 'Y' } type MethodProperties = { [Methods.X]: { x: string } [Methods.Y]: { y: string } } type Approach = { [method in keyof Method ...

Display Bootstrap Modal using Typescript in Angular

Looking for some creative ideas here... My Angular site allows users to register for events by filling out a form. They can also register themselves and other people at the same time. https://i.sstatic.net/a44I7.png The current issue ~ when a user clicks ...

"Encountering an error with the any type in the useLocation feature while using React Router version 6

https://i.sstatic.net/0YcS9.png What steps should I take to resolve this particular type of error issue? My attempt at passing a custom type did not yield successful results. ...

Is there a way to incorporate an "else" condition in a TypeScript implementation?

I am trying to add a condition for when there are no references, I want to display the message no data is available. Currently, I am working with ReactJS and TypeScript. How can I implement this check? <div className="overview-text"> < ...

Angular type error: Attempting to assign a value of type 'string' to a variable declared as type 'string[]' is not allowed

As a newcomer to Angular, I am currently working on building an electron app with Angular 6. My objective is: 1. Implementing SupportInformationClass with specific definitions 2. Initializing the component to populate the definitions from electron-settin ...

Is the autoIncrement property missing from the IDBObjectStore Interface in Typescript 1.8 lib.d.ts file?

Upon examining the specifications on various pages, it is evident that there is a specified read-only property named "autoIncrement" within the IDBObjectStore: https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore https://developer.mozilla.org/ ...

I obtained the binary tree output in the form of an object. How can I extract the values from this object and store them in an array to continue working on

Issue Statement In this scenario, you have been presented with a tree consisting of N nodes that are rooted at 1. Each node in the tree is associated with a special number, Se. Moreover, each node possesses a certain Power, which is determined by the count ...

The issue arises when interfaces are extended by another interface

Is there a way to have classes that implement both the Observer and Comparable interfaces together? interface Comparable<T> { equals: (item: T) => boolean; } interface Observer extends Comparable<Observer> { notify: () => void } ...

TypeScript async function that returns a Promise using jQuery

Currently, I am facing a challenge in building an MVC controller in TypeScript as I am struggling to make my async method return a deferred promise. Here is the signature of my function: static async GetMatches(input: string, loc?: LatLng):JQueryPromise& ...

Guide on integrating react-tether with react-dom createPortal for custom styling of tethered components based on their target components

Within a Component, I am rendering buttons each with its own tooltip. The challenge is to make the tooltip appear upon hovering over the button since the tooltip may contain more than just text and cannot be solely created with CSS. The solution involves ...

Iterating through typescript enums in Vue using v-for

Why is the v-for loop over an enum displaying both names and values? Is there a way to iterate only over the keys? export enum Colors { "RED" = 1, "BLUE" = 2, "GREEN" = 3, } <template> <div> <v ...

Using a promise as a filter callback in JavaScript: A guide

UPDATE: The solution can be found below I have a multitude of components that need to be filtered based on certain properties, but I am encountering an issue where I cannot resolve the promise before using it in the Array.filter() method. Here is my curr ...

Error: Exceeded Maximum Re-Renders. React has set a limit on the number of renders to avoid infinite loops. Issue found in the Toggle Component of Next.js

I am struggling with setting a component to only display when the user wants to edit the content of an entry, and encountering an error mentioned in the title. To achieve this, I have utilized setState to manage a boolean using toggle and setToggle, then ...

How can I change the CSS class of my navbar component in Angular 2 from a different component?

Here is a custom progress bar component I created: @Component ({ selector: 'progress-bar', templateUrl: './progress-bar.component.html', styleUrls: ['./progress-bar.component.css'] }) export class ProgressBarComponent ...

Can you explain to me the syntax used in Javascript?

I'm a bit puzzled by the syntax used in this react HOC - specifically the use of two fat arrows like Component => props =>. Can someone explain why this works? const withLogging = Component => props => { useEffect(() => { fetch(`/ ...

What is the best way to form a new type that encompasses all shared properties found within a union of types?

Is there a method to safely map over the union of arrays without hard-coding specific types? When attempting to calculate newArr1, an error is encountered: Property 'field2' does not exist on type 'Common<A, B>'. How can this err ...

Is it possible to compile TypeScript modules directly into native code within the JavaScript data file?

I am seeking a way to break down an app in a TypeScript development environment into separate function files, where each file contains only one function. I want to achieve this using TS modules, but I do not want these modules to be imported at runtime in ...

Guide to create a React component with passed-in properties

Currently in the process of transitioning a react project from redux to mobx, encountering an issue along the way. Previously, I utilized the container/presenter pattern with redux and the "connect" function: export default connect(mapStateToProps, mapDi ...

Error TS2322 occurs during compilation in Typescript when using ng.IPromise

Having some issues while using Angular 1.x with Typescript. Here is the code causing trouble: get(id): ng.IPromise<Server.MyItem> { return this.$http.get(`${this.baseAddress}/${id}`).then(d => d.data); } After compiling with tsc, I am encoun ...