【问题标题】:Mixin returns a subclass of an abstract class, how do I specify the mixin's return type?Mixin 返回一个抽象类的子类,如何指定 mixin 的返回类型?
【发布时间】:2021-07-22 06:49:55
【问题描述】:

我有一个 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;
}

如果我尝试从 mixin 结果进行扩展,这是我想要做的):

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"

【问题讨论】:

    标签: typescript typescript-typings mixins typescript-generics


    【解决方案1】:

    您的示例中Mixin 函数的返回类型是Constructor&lt;MixinBase&lt;T&gt;&gt;。 IE。 MixinBase 的构造函数,而不是您想要的 MixinClass。函数本身进行类型检查,因为 MixinClass 可分配给 MixinBase,因为它扩展了它。

    但后来class FooExample extends Mixin(FooPrinterService) {}“认为”它正在扩展MixinBase并失败了,因为MixinBase是抽象的,并且至少根据类型,printName尚未实现。

    像这样修改Mixin,让打字稿推断返回类型有效:

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

    (playground link)

    typescript 手册在这里有一个关于 mixins 的页面:https://www.typescriptlang.org/docs/handbook/mixins.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-29
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2011-12-27
      • 1970-01-01
      • 2016-06-08
      • 2020-07-03
      相关资源
      最近更新 更多