简体   繁体   中英

Return constructor of generic type in TypeScript

I'm struggling to define how to write TypeScipt code which says that function return constructor of generic type. There are plenty of examples around about how to pass constructor of the generic type, but not how to return.

Please check the following example:

This is part of the abstract class:

 getModel():  (new () => T) {
    throw new Error('Method not implemented.'); // Error because don't know how to fix it
}

When in derived class I'm trying to implement it like this:

getModel(): typeof User {
    return User;
}

I have the following error:

Type '() => typeof User' is not assignable to type '() => new () => User'.

I could skip implementation in the derived class if I knew how to specify in the abstract class.

So question is - how to specify on an abstract class level that method returns constructor of the generic type and I can skip implementation of this method at child level class? Or maybe I specify return signature not correctly on the abstract class level?

EDIT:

Please check the strange problem. Class A and B differ only by the presence of explicit constructor. And in RealA doesn't work and RealB works the same getModel() method.

class A {
a = '';
constructor(a: string) {

}
}

class B {
    a = '';
    static test(): void {
        console.log('I do work');
    }
}

abstract class Base<T> {
    Prop: T;
    constructor(TCreator: { new (): T; }) {
        this.Prop = new TCreator();
    }

    getModel(): (new () => T) {
        throw new Error('Method not implemented.'); // Error because don't know how to fix it
    }
}

class RealA extends Base<A> {
    getModel(): typeof A { // doesn't work - compilation error
        return A;
    }
}

class RealB extends Base<B> {
    getModel(): typeof B { // works
        return B;
    }
}

var test = new RealA(A); // compile error
var test2 = new RealB(B)

For RealA class the same error

() => typeof A' is not assignable to type '() => new () => A'

The error is expected as the constructor for class A has a required argument. The abstract class constrains the constructor to be passed it to have no arguments ( new () => T ).

The simple solution is to remove the constructor to A .

If you want to be able to pass in classes that have constructors that require arguments you will need to change the definition of the base class to capture the constructor type, and have the constructor take in those required arguments (using tuples in rest parameters )

class A {
    a = '';
    constructor(a: string) {

    }
}

class B {
    a = '';
    static test(): void {
        console.log('I do work');
    }
}

type ArgumentTypes<T> = T extends new (...a: infer A) => any? A : [] 
abstract class Base<T extends new (...a: any[])=> any> {
    Prop: InstanceType<T>;
    constructor(TCreator: T, ...a: ArgumentTypes<T>) {
        this.Prop = new TCreator(...a);
    }

    getModel(): T {
        throw new Error('Method not implemented.'); // Error because don't know how to fix it
    }
}

class RealA extends Base<typeof A> {
    getModel(): typeof A { // doesn't work - compilation error
        return A;
    }
}

class RealB extends Base<typeof B> {
    getModel(): typeof B { // works
        return B;
    }
}

var test = new RealA(A, ""); // ok
var test2 = new RealB(B)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM