首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在TypeScript中,如何从接口引用实现类?

在TypeScript中,如何从接口引用实现类?
EN

Stack Overflow用户
提问于 2022-01-06 17:09:48
回答 1查看 319关注 0票数 4

我正在通过实现梦幻之地规格来探索类型记录类型系统,在实现半群规范时遇到了一个问题。

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

代码语言:javascript
复制
concat :: Semigroup a => a ~> a -> a

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

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

代码语言:javascript
复制
interface Semigroup {
    concat(other: this): this;
}

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

代码语言:javascript
复制
class Sum implements Semigroup {
    constructor(readonly num: number) {}

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

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

代码语言:javascript
复制
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的类也可以传入。

但是,我不知道怎么解决它。也就是说,我不知道如何用TypeScript来表示TypeScript的类型定义。如何从接口引用实现类?

这里是TS游乐场的链接

更新

@Guerric的回答让我想到了一个部分的解决方案。Guerric的解决方案是在界面上使用泛型。这个解决方案使实现Semigroup规范成为可能,如这里所示,但是接口并没有真正地强制执行它。

“幻想世界”进一步描述了该规范如下:

代码语言:javascript
复制
s.concat(b)

/** 
 * `b` must be a value of the same `Semigroup`
 *
 * If `b` is not the same semigroup, behaviour of `concat` is 
 * unspecified.
 *
 * `concat` must return a value of the same `Semigroup`.
 */

与其使b成为泛型,我认为我们至少可以将该类型限制为Semigroup。这样,它执行了b必须是Semigroup类型的约束,如下所示:

代码语言:javascript
复制
interface Semigroup {
    concat(other: Semigroup): Semigroup;
}

但它仍然没有强制要求它必须是相同的Semigroup。我仍然在寻找一种在TypeScript类型系统中实现这种功能的方法。

EN

回答 1

Stack Overflow用户

发布于 2022-01-06 18:13:05

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

问题是您的class可以扩展,所以this可以引用该扩展类。在final class或TypeScript中没有类似的东西。

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

但是,您的concat实现不能工作,因为(other: Sum) => Sum不能分配给(other: ExtendedSum) => ExtendedSum。实际上,返回Sum的函数不能分配给返回ExtendedSum的函数,因为Sum不一定是,也不一定是ExtendedSum

您可以通过泛型类型化接口修复这个问题:

代码语言:javascript
复制
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游乐场

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70610877

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档