【问题标题】:Typescript interface/implementation ctor signature mismatch - why?Typescript 接口/实现 ctor 签名不匹配 - 为什么?
【发布时间】:2018-02-07 12:57:35
【问题描述】:

为什么构造函数签名与以下摘录中的接口声明不匹配,我应该如何重新表达它?报错是

'Class 'Item' 错误地实现了接口 'ItemClass'。 类型“项目”不匹配签名“新(范围?:范围 | 未定义):项目”。

这段代码的重点是工厂支持在运行时由来自类序列化的字符串名称标识的子类。抽象的 AsyncCtor 定义并初始化了一个 Ready 属性。我可以直接在

export interface ItemClass {
  Ready: Promise<any>;
  new(Scope?: Scope): Item;
}

export abstract class AsyncCtor {
  public Ready: Promise<any> = new Promise((resolve, reject) => resolve(undefined));
}

export abstract class Item extends AsyncCtor implements ItemClass {
  static Type: Map<string, ItemClass> = new Map<string, ItemClass>();
  static register(typeName: string, typeClass: ItemClass): void {
    this.Type.set(typeName, typeClass);
  }
  public static new(raw: any): Item {
    let graph = typeof raw === "string" ? JSON.parse(raw) : raw;
    let typeClass = Item.Type.get(graph.Type) as ItemClass;
    let item = new typeClass();
    ...
    return item;
  }
  constructor(public Scope?: Scope) {
    super();
  }
}

如果我停止声明 Item 实现 ItemClass 的事实,一切都会编译并且 Item.new(raw) 方法工作正常,所以显然它确实实现了 ItemClass。

在有人建议之前,我已经尝试过了

  constructor(public Scope?: Scope | undefined) {

【问题讨论】:

  • 谢谢。在我看来,我的问题几乎是重复的,其主要优点是它将帮助来自这个方向的人们找到理解。如果您愿意重申您的评论作为答案,我愿意接受。
  • Nitzan 的答案是正确的,当您在Item 中有正确的constructor 和正确的静态方法时,Item 的静态部分符合ItemClass,您可以使用任何Item 的非抽象后代作为 register 的第二个参数,没有明确声明它实现了 ItemClass(打字稿中的兼容性始终是结构性的)。另见stackoverflow.com/questions/39362690/…

标签: typescript constructor interface


【解决方案1】:

您将静态类方法与实例方法混合在一起。

它应该看起来像:

type ItemClassConstructor = {
    new (Scope?: Scope): Item;
    create(raw: any): Item;
}

interface ItemClass {
    Ready: Promise<any>;
}

abstract class Item extends AsyncCtor implements ItemClass {
    static Type: Map<string, ItemClassConstructor> = new Map<string, ItemClassConstructor>();
    static register(typeName: string, typeClass: ItemClassConstructor): void {
        this.Type.set(typeName, typeClass);
    }

    public static create(raw: any): Item {
        let graph = typeof raw === "string" ? JSON.parse(raw) : raw;
        let typeClass = Item.Type.get(graph.Type);
        let item = new typeClass();

        return item;
    }

    constructor(public Scope?: Scope) {
        super();
    }
}

(code in playground)

【讨论】:

  • 不,我不是,虽然它确实看起来像那样,但我会采纳你的暗示建议以避免将静态方法命名为“新”。在接口中new 指的是一个新的函数,即构造函数。这在 artem 评论中引用的问题中得到了阐述 - 这也很好地解释了真正的问题。
  • 但是你的方法是static,你不能把它放在一个接口中,然后扩展那个接口期望它工作。静态方法应该放在另一个你不能扩展的接口/类型中,就像我对 ItemClassConstructor 类型所做的那样。
  • 正如我已经说过的,接口中的 new 指的是构造函数。这是一个糟糕的名称选择,因为它会引起您正在经历的混乱。如果我将静态 new 方法重命名为 create,则从编译器的角度来看,代码具有完全相同的语义。
  • 但是new,就像一个静态方法不能是implemented,它们不是实例方法。这就是为什么我将它们放在称为ItemClassConstructor 的不同类型中。
猜你喜欢
  • 2019-08-12
  • 1970-01-01
  • 2019-12-04
  • 2016-11-30
  • 1970-01-01
  • 2016-06-20
  • 2018-09-14
  • 2018-02-23
  • 2020-02-12
相关资源
最近更新 更多