【问题标题】:Strange behaivour of TypeScript when extending class with similar namespace structure扩展具有相似命名空间结构的类时 TypeScript 的奇怪行为
【发布时间】:2021-12-29 13:27:38
【问题描述】:

最近我一直在尝试为用 JS 编写的库创建一个类型库。当我声明所有命名空间、类和接口时,一些类开始给我一个错误TS2417。我检查了方法或属性的无效覆盖是否有任何问题,但我找不到任何东西。一段时间后,我发现有问题的类与命名空间之一具有相同的名称(例如类A.B 和命名空间A.B)。但这并没有造成任何麻烦。问题是(有问题的类的)父类有,就像有问题的类一样,命名空间完全相同,这个命名空间和有问题的类的命名空间有类,它的命名完全相同,但有不同的界面(我很难描述这个问题,所以我simulated here)。

所以问题是,是什么导致了这个问题?

在此示例中,有问题的类是 A.C,但由于类 A.C.XA.B.X 的构造函数不兼容而出现问题。

declare namespace A {
  class B {

  }

  namespace B {
    class X {

    }
  }

  class C extends A.B {

  }

  namespace C {
    class X {
      constructor(x: number)
    }
  }
}

【问题讨论】:

  • 这里的问题具体是什么?是“为什么会这样?”如果是这样,那是因为A.C 被声明为extends A.B,但它不能分配给A.B。也就是说,您应该能够编写const c: typeof A.B = A.C 然后编写new c.X() 没有问题,但是A.C.X 的构造函数需要number 参数。所以你冒着运行时错误的风险,比如this。请注意,在此示例中,我已将所有声明替换为具体实现,但这是完全相同的问题。如果这是有道理的,我可以写一个答案。如果我遗漏了什么,请告诉我。
  • @jcalz 很抱歉忘记提出具体问题,但您是对的。我只是想知道为什么会这样,现在我明白了,谢谢!
  • 好的,有机会我会写一个答案的。

标签: javascript typescript oop types


【解决方案1】:

(下面我将省略命名空间A

除了construct signature 之外,classstatic 端检查substitutability 的方式与实例端相同;所以如果你有class X { static prop: string = "" },那么你就不能有class Y extends X { static prop: number = 2}。当您说class Y extends X 时,您声明除其他外,Y.prop 可分配给X.prop。有关更多信息,请参阅microsoft/TypeScript#4628。不是每个人都喜欢这种约束,但它确实存在。


这意味着以下应该可以正常工作:

const X: typeof B.X = C.X; // should be okay
new X(); // should be okay

但是你的类的具体实现很容易导致运行时错误:

class B {
  static X = class { }
}

class C extends B {
  static X = class {
    constructor(x: number) {
      x.toFixed();
    }
  }
}

这里,C.X 是一个需要 number 输入的类构造函数。但是B.X 是一个类构造函数,根本不需要任何输入。如果您将前者视为后者,那么在运行时您将在undefined 上调用toFixed() 方法。哎呀。

这就是class C extends B 生成编译器错误的原因;保护您免受类的静态方面引起的可替代性问题。

Playground link to code

【讨论】:

    猜你喜欢
    • 2012-08-26
    • 2017-08-26
    • 1970-01-01
    • 2011-03-27
    • 2021-11-29
    • 2023-01-13
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    相关资源
    最近更新 更多