我试图创建一个将类作为参数(不是类实例,而是类本身)并返回另一个扩展参数中给出的类的函数。
我尝试如下定义打字稿功能,但出现以下错误: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函数的正确类型定义是什么?
答案 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() { }
}
}
您可以在代码中使用此类型,它应能按预期工作。