我有一个 mixin,它返回一个抽象类的具体实现。一切都很好地结合在一起,直到我尝试扩展 mixin 返回的类,此时 TypeScript 抱怨我的新子类没有实现抽象方法。
我想我明白为什么会发生这种情况,但是我找不到一种方法来通知类型系统我没有返回抽象类,而是返回一个具体的子类。
这是一个简化示例 (plaground link):
export class PrinterService {
public print(value: string): void {
console.log(value);
}
}
export class FooPrinterService extends PrinterService {
public print(value: string): void {
console.log(`FOO: ${value}`);
}
}
export class BarPrintService extends PrinterService {
public print(value: string): void {
console.log(`BAR: ${value}`);
}
}
export abstract class MixinBase<T extends PrinterService> {
constructor(
public service: T,
public name: string = 'Abstract') {}
abstract printName(): void;
}
export type Constructor<T> = new (...args: any[]) => T;
export function Mixin<T extends PrinterService>(ServiceClass: Constructor<T>): Constructor<MixinBase<T>> {
class MixinClass extends MixinBase<T> {
constructor(service: T = new ServiceClass(), name = 'Mixin') {
super(service, name);
}
public printName(): void {
this.service.print(this.name);
}
}
return MixinClass;
}
如果我尝试从混合结果中扩展,这是我想要做的):
class FooExample extends Mixin(FooPrinterService) {}
// Non-abstract class 'FooExample' does not implement inherited abstract member
// 'printName' from class 'MixinBase<FooPrinterService>'.ts(2515)
有趣的是,如果我直接实例化结果,我不会抱怨:
const bar = new (Mixin(BarPrintService))(undefined, 'Bar');
bar.printName();
// prints "BAR: bar"
答案 0 :(得分:0)
示例中 Mixin
函数的返回类型是 Constructor<MixinBase<T>>
。 IE。 MixinBase
的构造函数,而不是您想要的 MixinClass
。函数本身进行类型检查,因为 MixinClass
可分配给 MixinBase
,因为它扩展了它。
但后来 class FooExample extends Mixin(FooPrinterService) {}
“认为”它正在扩展 MixinBase
并且失败了,因为 MixinBase
是抽象的,并且至少根据类型,printName
尚未实现.
像这样修改 Mixin
,并让 typescript 推断返回类型有效:
export function Mixin<T extends PrinterService>(ServiceClass: Constructor<T>) {
return class MixinClass extends MixinBase<T> {
constructor(service: T = new ServiceClass(), name = 'Mixin') {
super(service, name);
}
public printName(): void {
this.service.print(this.name);
}
}
}
打字稿手册在这里有一个关于 mixin 的页面:https://www.typescriptlang.org/docs/handbook/mixins.html