java - TypeScript 与 Java 中的接口(interface)

标签 java typescript

这在 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 的定义与此限制冲突;它不能声明为同时扩展 BBetterAB 有一个 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 当你被要求输入 YZ 时。 TypeScript 没有这样的限制:如果 X 的结构与 YZ 兼容,您可以使用 X 代替 YZ 即使 X 的声明没有提到 YZ 显式。

这意味着如果我们可以弄清楚我们希望在 BetterB 上看到哪些成员名称和类型,我们可以将 BetterB 定义为具有该形状而无需明确说明扩展 B,BetterA。如果我们做对了,它会自动扩展这些接口(interface)。

我能想到的最简单的方法是:

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

这里我们仍然扩展BetterA,但我们没有显式扩展所有B,而是使用Pick utility type。也就是说,我们只想用 getSomeBetterA 成员扩展 B 的部分。有问题的 getBasicA 方法被排除在外,因此没有错误。由于 BetterAgetBasicA 方法可分配给 BgetBasicA 方法,BetterB 仍然在结构上扩展了 B,如下所示:

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

BetterB 类型的值赋给B 类型的变量没有错误。您没有声明 BetterB extends B 但它还是发生了。


Playground link to code

关于java - TypeScript 与 Java 中的接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65539933/

相关文章:

java - java中的通用日期解析

java - java中无法识别uint8_t的字符串转换

java - import class.1 是什么意思?

javascript - aurelia property observer 未被处置

typescript - 调用签名和函数类型之间的区别

java - 编辑距离代码中的 NZEC

java - Java 中的 apache poi 和 swing 问题

具有动态参数的 Angular Factory Provider

Angular2 和 TypeScript 错误 "Property METHOD_NAME does not exist on type ' typeof CLASS_NAME'

javascript - Angular2/Typescript/ngRx - 类型错误 : Cannot assign to read only property of object