繁体   English   中英

在 TypeScript 中,您如何表示在接口 I 中声明的类型 T 应该是将实现所述接口 I 的任何类型 U

[英]In TypeScript, how do you express that a type T, declared inside an interface I, should be of whatever type U that will implement said interface I

我正在通过实现Fantasy Land Spec来探索 Typescript 类型系统,但在尝试实现Semigroup的规范时遇到了问题。

规范规定Semigroup应遵守以下类型定义:

concat :: Semigroup a => a ~> a -> a

我理解这意味着实现Semigroup的类型a应该有一个concat方法,该方法接受 a 类型a参数并返回 a 类型a参数。

我能想到在 TypeScript 中表达这种类型定义的唯一方法是:

interface Semigroup {
    concat(other: this): this;
}

但是当我尝试在 class 上实现这个接口时,像这样:

class Sum implements Setoid, Semigroup {
    constructor(readonly num: number) {}

    concat(other: Sum): Sum {
        return new Sum(this.num + other.num);
    }
}

我收到一个编译器错误,告诉我:

Property 'concat' in type 'Sum' is not assignable to the same property in base type 'Semigroup'.
  Type '(other: Sum) => Sum' is not assignable to type '(other: this) => this'.
    Type 'Sum' is not assignable to type 'this'.
      'Sum' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Sum'.(2416)

感谢这个S/O 答案,我想我理解了这个问题。

我认为编译器本质上是在告诉我:您的界面说您应该采用具体类型的参数this (在这种特殊情况下为Sum ),但是也可以传入扩展Sum的 class 。

但是,我不知道如何解决它。 就是不知道Semigroup中Semigroup的类型定义怎么表达。 如何表示在接口 I 中声明的类型 T 应该是实现所述接口 I 的任何类型 U?

这是 TS Playground 的链接

我不想质疑您对幻想土地规范的解释,我承认我并不完全理解,所以我假设您的解释是正确的。

问题是您的class可以扩展,所以this可以指扩展的 class。 TypeScript 中没有final class或等效项。

现在假设您有一个扩展SumExtendedSum class 。 您的equals实现仍然有效,因为(other: Sum) => boolean可分配给(other: ExtendedSum) => boolean 实际上,将Sum作为参数的 function 也可以采用ExtendedSum (结构类型原则)。

但是,您的concat实现不起作用,因为(other: Sum) => Sum不能分配给(other: ExtendedSum) => ExtendedSum 实际上,返回Sum的 function 不能分配给返回ExtendedSum的 function ,因为Sum不一定ExtendedSum

您可以使用通用类型接口解决此问题:

interface Semigroup<T> {
    concat(other: T): T;
}

class Sum implements Setoid, Semigroup<Sum> {
    constructor(readonly num: number) {}

    equals(other: Sum): boolean {
        return this.num === other.num;
    }

    concat(other: Sum): Sum {
        return new Sum(this.num + other.num);
    }
}

TypeScript操场

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM