typescript与java中的接口

b91juud3  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(434)

这在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编译器允许它)?有一个编译器支持而另一个不支持的特性的名称吗?

s4n0splo

s4n0splo1#

仅仅因为它在java中工作并不意味着它应该在typescript上工作。这是两件完全不同的事情。对于初学者来说,typescript依赖于duck类型,而java则不依赖。
如果您想组合多个接口,最好使用Map类型,而不是多次扩展。
我在媒体上写的,看看,可能会有帮助

toiithl6

toiithl62#

如您所见,typescript要求在通过逗号表示法扩展多个接口时(例如。, interface X extends Y, Z { ... } ),多个父接口共用的任何成员名称都需要具有相同的类型。
定义 BetterB 违反这一限制;它不能同时声明为 B 以及 BetterA . B 有一个 getBasicA 类型的成员 () => A ,而 BetterA 有一个 getBasicA 类型的成员 () => BetterA . 这些类型是不相同的,因此会出现一个错误,最终导致整个问题的解决,因为接口定义是递归的。
要求多个接口的扩展中的公共属性具有相同的类型,这可能比它需要的限制性更强。microsoft/typescript#16936上有一个开放的特性请求,请求允许普通成员具有不相同但“兼容”的类型(可能意味着这些类型有一些重叠)。在这种情况下,行为应该是什么还不是100%清楚;新接口的属性类型可能是每个父接口的属性类型的交集,或者可能会发生一些更复杂的选择过程。但无论如何,它并不是ts4.1语言的一部分。
重申一下:并不是说你要做的不是类型安全的,只是不支持。
那么,你能做什么?typescript值得注意的一点是,类型系统是结构化的,而不是像java中那样是标称的。类型在typescript中是通过它们的形状进行比较的,而不是通过它们的声明。在java中,如果你不能声明 interface X extends Y, Z ,则不能使用 X 当你被要求 Y 或者 Z . typescript没有这样的限制:if X 的结构与两者兼容 Y 以及 Z ,您可以使用 X 代替 Y 或者 Z 即使 X 没有提到 Y 或者 Z 明确地。
这意味着如果我们能弄清楚我们希望看到什么样的成员名和类型 BetterB ,我们可以定义 BetterB 没有明确说明的形状 extends B, BetterA . 如果我们做对了,它会自动扩展这些接口。
我能想到的最简单的方法是:

interface BetterB extends Pick<B, "getSomeBetterA">, BetterA { }

在这里,我们仍在扩展 BetterA ,而不是显式扩展 B ,我们正在使用 Pick 实用类型说,我们只想扩展的一部分 B 用一个 getSomeBetterA 成员。冒犯者 getBasicA 方法被排除,因此没有错误。从那以后呢 BetterAgetBasicA 方法可分配给 BgetBasicA 方法, BetterB 仍然延伸 B 从结构上看,如图所示:

declare const bB: BetterB;
const b: B = bB; // okay

分配类型的值时没有错误 BetterB 类型的变量 B . 你没有申报 BetterB extends B 但事情还是发生了。
操场链接到代码

相关问题