使用类似命名空间结构扩展 class 时 TypeScript 的奇怪行为
Strange behaivour of TypeScript when extending class with similar namespace structure
最近我一直在尝试为用JS编写的库创建一个类型库。当我声明所有命名空间、classes 和接口时,一些 classes 开始给我一个错误 TS2417
。我检查了是否存在无效覆盖方法或属性的问题,但我找不到任何东西。一段时间后,我发现有问题的 class 与命名空间之一同名(例如 class A.B
和命名空间 A.B
)。但这并没有造成任何麻烦。问题是(有问题的 class 的父 class 和有问题的 class 一样,命名空间完全相同,这个命名空间和有问题的 class 的命名空间=27=] 有 class,名称完全相同,但界面不同(我很难描述这个问题,所以我 simulated here)。
所以问题是,是什么导致了这个问题?
在此示例中,有问题的 class 是 A.C
,但由于 classes A.C.X
和 A.B.X
的构造函数不兼容,它会出现问题。
declare namespace A {
class B {
}
namespace B {
class X {
}
}
class C extends A.B {
}
namespace C {
class X {
constructor(x: number)
}
}
}
(下面我会省去命名空间A
)
除 construct signature, the static
side of a class
is checked for substitutability the same way that the instance side is; so if you have class X { static prop: string = "" }
, then you can't have class Y extends X { static prop: number = 2}
. When you say class Y extends X
you are declaring that, among other things, Y.prop
is assignable to X.prop
. See microsoft/TypeScript#4628 以外的更多信息。不是每个人都喜欢这种限制,但它确实存在。
这意味着以下内容应该可以正常工作:
const X: typeof B.X = C.X; // should be okay
new X(); // should be okay
但是您的 classes 的具体实现很容易导致运行时错误:
class B {
static X = class { }
}
class C extends B {
static X = class {
constructor(x: number) {
x.toFixed();
}
}
}
此处,C.X
是一个 class 构造函数,需要 number
输入。但是 B.X
是一个 class 构造函数,它根本不需要任何输入。如果您将前者视为后者,那么在运行时您将在 undefined
上调用 toFixed()
方法。哎呀
这就是 class C extends B
生成编译器错误的原因;保护您免受 class.
的静态方面引起的可替代性问题
最近我一直在尝试为用JS编写的库创建一个类型库。当我声明所有命名空间、classes 和接口时,一些 classes 开始给我一个错误 TS2417
。我检查了是否存在无效覆盖方法或属性的问题,但我找不到任何东西。一段时间后,我发现有问题的 class 与命名空间之一同名(例如 class A.B
和命名空间 A.B
)。但这并没有造成任何麻烦。问题是(有问题的 class 的父 class 和有问题的 class 一样,命名空间完全相同,这个命名空间和有问题的 class 的命名空间=27=] 有 class,名称完全相同,但界面不同(我很难描述这个问题,所以我 simulated here)。
所以问题是,是什么导致了这个问题?
在此示例中,有问题的 class 是 A.C
,但由于 classes A.C.X
和 A.B.X
的构造函数不兼容,它会出现问题。
declare namespace A {
class B {
}
namespace B {
class X {
}
}
class C extends A.B {
}
namespace C {
class X {
constructor(x: number)
}
}
}
(下面我会省去命名空间A
)
除 construct signature, the static
side of a class
is checked for substitutability the same way that the instance side is; so if you have class X { static prop: string = "" }
, then you can't have class Y extends X { static prop: number = 2}
. When you say class Y extends X
you are declaring that, among other things, Y.prop
is assignable to X.prop
. See microsoft/TypeScript#4628 以外的更多信息。不是每个人都喜欢这种限制,但它确实存在。
这意味着以下内容应该可以正常工作:
const X: typeof B.X = C.X; // should be okay
new X(); // should be okay
但是您的 classes 的具体实现很容易导致运行时错误:
class B {
static X = class { }
}
class C extends B {
static X = class {
constructor(x: number) {
x.toFixed();
}
}
}
此处,C.X
是一个 class 构造函数,需要 number
输入。但是 B.X
是一个 class 构造函数,它根本不需要任何输入。如果您将前者视为后者,那么在运行时您将在 undefined
上调用 toFixed()
方法。哎呀
这就是 class C extends B
生成编译器错误的原因;保护您免受 class.