-1

I am working on the universal abstraction/base of the async constructor and it works fine with JavaScript.

But I'm stuck with correct TypeScript types, it should work like this:

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

It works fine in JavaScript, but TypeScript types are wrong (missing at the moment).

Example of the similar class called 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 base class is:

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;
    }
}

What type to specify for the return of the create method?

8
  • 1
    Related: stackoverflow.com/q/68027725/3001761 Commented Feb 22, 2024 at 14:54
  • @jonrsharpe not really, since it doesn't provide any solution, at least partial. Also JavaScript version works perfectly. Commented Feb 22, 2024 at 15:00
  • 1
    I didn't say it provided a solution, I said it was related. The comment from jcalz explains why there likely isn't (or at least wasn't) a solution. And whether or not the JS works isn't the question - TS disallows plenty of things that work in JS, usually on purpose. Commented Feb 22, 2024 at 15:04
  • This comment on the github issue that's linked describes a factory method as well: github.com/microsoft/TypeScript/issues/… Immediately above that comment is a solution with generics that's a little verbose but it might do the trick. Commented Feb 22, 2024 at 16:27
  • 1
    "not possible to have interface that requires static members" - not during the inheritance/implements declaration, but it is possible to require them during the create invocation. Have a look at stackoverflow.com/a/72771370/1048572 for example. Here, it could be something like async create<T>(this: { new(c: Connection): T; createConnection(): Promise<Connection> }): T { return new this(await this.createConnection()); } Commented Mar 3, 2024 at 22:13

1 Answer 1

0

This is impossible as of 2024.02 due to the limitation of the TypeScript (for sure <= v.5.3)



The only possible partial solution as for now 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;
    }
}

The disadvantage of this approach is that you:

  • cannot force some classes to follow the same implementation
  • as a result, each class may have its unique name and way of creation
  • this may cause problems during the inheritance of complex classes, especially with the big code base
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.