这在 TypeScript 中失败了...
interface A {
getSomeBasicA():A;
getSomeBetterA():BetterA;
}
interface BetterA extends A {
getSomeBasicA():BetterA;
doFancyAStuff():void;
}
interface B extends A {
getSomeBetterA():BetterB;
}
interface BetterB extends B, BetterA {}
... 这条消息...
error TS2430: Interface 'B' incorrectly extends interface 'A'.
The types returned by 'getSomeBetterA().getSomeBasicA()' are incompatible between these types.
Property 'doFancyAStuff' is missing in type 'A' but required in type 'BetterA'.
error TS2320: Interface 'BetterB' cannot simultaneously extend types 'B' and 'BetterA'.
Named property 'getSomeBasicA' of types 'B' and 'BetterA' are not identical.
error TS2320: Interface 'BetterB' cannot simultaneously extend types 'B' and 'BetterA'.
Named property 'getSomeBetterA' of types 'B' and 'BetterA' are not identical.
...虽然这在 Java 中有效...
public interface A {
public A getSomeBasicA();
public BetterA getSomeBetterA();
}
public interface BetterA extends A {
public BetterA getSomeBasicA();
public void doFancyAStuff();
}
public interface B extends A {
public BetterB getSomeBetterA();
}
public interface BetterB extends B, BetterA {
}
...我想知道为什么?它不是类型安全的吗(它怎么会被破坏,为什么Java编译器允许它)?是否有一种编译器支持而另一种不支持的特性的名称?
最佳答案
如您所见,TypeScript 要求当 extending multiple interfaces通过逗号表示法(例如,interface X extends Y, Z { ... }
),多个父接口(interface)通用的任何成员名称都需要具有相同的类型.
BetterB
的定义与此限制冲突;它不能声明为同时扩展 B
和 BetterA
。 B
有一个 getBasicA
类型的成员 () => A
,而 BetterA
有一个 getBasicA
类型 () => BetterA
的成员。这些类型不相同,因此您会在那里遇到错误,这最终会导致整个事情变得复杂,因为您的接口(interface)定义是递归的。
多个接口(interface)扩展中的公共(public)属性具有相同类型的要求可能比需要的更严格。在 microsoft/TypeScript#16936 有一个开放的功能请求要求允许普通成员具有不同但“兼容”的类型(大概意味着这些类型有一些重叠)。并不是 100% 清楚在这种情况下应该采取什么行为;也许新接口(interface)的属性类型是 intersection来自每个父接口(interface)的属性类型,或者可能会发生一些更复杂的选择过程。但无论如何,它不是 TS4.1 语言的一部分。
重申一下:并不是说您尝试做的事情类型不安全,只是不受支持。
那么,你能做什么?关于 TypeScript 的一件值得注意的事情是类型系统是 structural而不是 Java 中的名义上的。在 TypeScript 中,类型是通过它们的形状来比较的,而不是通过它们的声明。在 Java 中,如果您不能声明 interface X extends Y, Z
,那么您就不能使用 X
当你被要求输入 Y
或 Z
时。 TypeScript 没有这样的限制:如果 X
的结构与 Y
和 Z
兼容,您可以使用 X
代替 Y
或 Z
即使 X
的声明没有提到 Y
或Z
显式。
这意味着如果我们可以弄清楚我们希望在 BetterB
上看到哪些成员名称和类型,我们可以将 BetterB
定义为具有该形状而无需明确说明扩展 B,BetterA
。如果我们做对了,它会自动扩展这些接口(interface)。
我能想到的最简单的方法是:
interface BetterB extends Pick<B, "getSomeBetterA">, BetterA { }
这里我们仍然扩展BetterA
,但我们没有显式扩展所有B
,而是使用Pick
utility type。也就是说,我们只想用 getSomeBetterA
成员扩展 B
的部分。有问题的 getBasicA
方法被排除在外,因此没有错误。由于 BetterA
的 getBasicA
方法可分配给 B
的 getBasicA
方法,BetterB
仍然在结构上扩展了 B
,如下所示:
declare const bB: BetterB;
const b: B = bB; // okay
将BetterB
类型的值赋给B
类型的变量没有错误。您没有声明 BetterB extends B
但它还是发生了。
关于java - TypeScript 与 Java 中的接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65539933/