返回扩展匿名类的函数的类型定义

时间:2018-12-08 22:30:13

标签: typescript

我试图创建一个将类作为参数(不是类实例,而是类本身)并返回另一个扩展参数中给出的类的函数。

我尝试如下定义打字稿功能,但出现以下错误:Type 'typeof (Anonymous class)' is not assignable to type 'T'

function extendClass<T>(base: T): T  {
    return class extends base{
    };
}

我上面函数的示例用法:

class A {
}

const B = extendClass(A); // B is an extended class of A

let b = new B(); // b is instance of class B

extendClass函数的正确类型定义是什么?

2 个答案:

答案 0 :(得分:2)

您需要确保传递给extendClass的参数是类,而不是实例。在类型级别上,类可以表示为 newable函数

new (...args: any[]) => any

要使其更具可读性,我们给它起一个别名。

interface Constructable {
    new (...args: any[]): any;
}

现在我们拥有了所需的一切!

function extendClass<T extends Constructable>(Base: T) {
    return class extends Base {};
};

返回类型,但是,手工编写有点麻烦,因为它需要同时处理返回的类的类型和原型链。我们可以使用类型推断为我们完成工作:

function extendClass<T extends Constructable>(BaseClass: T): typeof DerivedClass {
    const DerivedClass = class extends BaseClass {};

    return DerivedClass;
}

将派生类分配给局部变量只是为了我们可以读取和使用其推断类型。

答案 1 :(得分:1)

您需要指定T是构造函数,以便能够将其用作函数中匿名类的基类。关于返回类型,我的建议是让编译器推断出这一点。 T

如果匿名类未添加任何您不想从函数外部访问的成员,则可以仅使用T作为返回类型,但是如果您添加成员,则仅允许编译器进行推断。

function extendClass<T extends new (...a: any[])=> any>(base: T)  {
    return class extends base{
    };
}
class A {
}

const B = extendClass(A); // B is an extended class of A
type B = InstanceType<typeof B>

let b:B = new B(); // b is instance of class B

如果您不添加公共成员,则可以使用T作为返回类型:

export function extendClass<T extends new (...a: any[]) => any>(base: T): T {
    return class extends base {
    }
}

如果您离开推断的版本并生成声明,则实际上可以看到,如果我们向T添加成员,将如何显式声明返回类型:

export function extendClass<T extends new (...a: any[]) => any>(base: T): {
    new (...a: any[]): {
        test(): void;
    };
} & T {
    return class extends base {
        test() { }
    }
}

您可以在代码中使用此类型,它应能按预期工作。