简体   繁体   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

I'm exploring the Typescript type system by implementing the Fantasy Land Spec and I ran into an issue while trying to implement the spec for Semigroup .我正在通过实现Fantasy Land Spec来探索 Typescript 类型系统,但在尝试实现Semigroup的规范时遇到了问题。

The spec stipulates that a Semigroup should adhere to the following type definition:规范规定Semigroup应遵守以下类型定义:

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

I understand this to mean that a type a , which implements Semigroup , should have a concat method that takes in a parameter of type a and returns a parameter of type a .我理解这意味着实现Semigroup的类型a应该有一个concat方法,该方法接受 a 类型a参数并返回 a 类型a参数。

The only way I could think of expressing this type definition in TypeScript is this:我能想到在 TypeScript 中表达这种类型定义的唯一方法是:

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

But when I try to implement this interface on a class, like this:但是当我尝试在 class 上实现这个接口时,像这样:

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

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

I get a compiler error telling me that:我收到一个编译器错误,告诉我:

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)

Thanks to this S/O answer, I think I understand the problem.感谢这个S/O 答案,我想我理解了这个问题。

I think the compiler is essentially telling me: your interface says that you should be taking a parameter that is of the concrete type this ( Sum in this particular case), but a class that extends Sum could also be passed in.我认为编译器本质上是在告诉我:您的界面说您应该采用具体类型的参数this (在这种特殊情况下为Sum ),但是也可以传入扩展Sum的 class 。

However, I don't know how to fix it.但是,我不知道如何解决它。 That is, I don't know how to express the type definition for Semigroup in TypeScript.就是不知道Semigroup中Semigroup的类型定义怎么表达。 How does one express that a type T, declared inside an interface I, should be of whatever type U that will implement said interface I?如何表示在接口 I 中声明的类型 T 应该是实现所述接口 I 的任何类型 U?

Here is link to a TS Playground.这是 TS Playground 的链接

I don't want to question your interpretation of that fantasy-land spec, which I admit I don't fully understand, so I'll assume your interpretation is right.我不想质疑您对幻想土地规范的解释,我承认我并不完全理解,所以我假设您的解释是正确的。

The problem is that your class could be extended, so this could refer to that extended class.问题是您的class可以扩展,所以this可以指扩展的 class。 There is no such thing as final class or equivalent in TypeScript. TypeScript 中没有final class或等效项。

Now let's suppose you have an ExtendedSum class which extends Sum .现在假设您有一个扩展SumExtendedSum class 。 Your equals implementation still works because (other: Sum) => boolean is assignable to (other: ExtendedSum) => boolean .您的equals实现仍然有效,因为(other: Sum) => boolean可分配给(other: ExtendedSum) => boolean Indeed, a function that takes a Sum as parameter can take an ExtendedSum as well (structural typing principle).实际上,将Sum作为参数的 function 也可以采用ExtendedSum (结构类型原则)。

However, your concat implementation doesn't work because (other: Sum) => Sum is not assignable to (other: ExtendedSum) => ExtendedSum .但是,您的concat实现不起作用,因为(other: Sum) => Sum不能分配给(other: ExtendedSum) => ExtendedSum Indeed, a function that returns a Sum is not assignable to a function that returns an ExtendedSum because a Sum is not necessarily an ExtendedSum .实际上,返回Sum的 function 不能分配给返回ExtendedSum的 function ,因为Sum不一定ExtendedSum

You could fix that with a generic typed interface:您可以使用通用类型接口解决此问题:

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 playground TypeScript操场

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

相关问题 在 TypeScript 中,如何使用 (a: type, b:type): any 实现接口? - In TypeScript, how do I implement an interface with (a: type, b:type): any? 我如何告诉 TypeScript 接口 T 比具有索引签名的类型 U 窄? - How do I tell TypeScript that interface T is narrower than type U which has an index signature? 为什么我不能在打字稿类中定义接口或类型 - why i can't define interface or type inside typescript class 在打字稿中,如何实现带有回调的接口? - in typescript, how do I implement a interface with a callback? 如何在打字稿中的接口中指定回调,而不必为其命名类型 - How do I specify a callback in an interface in typescript but not have to name a type for it Typescript 如何扩展使用泛型类型的接口? - Typescript how do I extend an interface which uses a generic type? 如何使用对接口中属性的引用作为 TypeScript 中的类型? - How do I use a reference to a property in an interface as a type in TypeScript? 如何在Typescript接口文件中表示返回类型? - How do I represent a return type in a Typescript interface file? 如何在打字稿中的类方法上强制执行函数类型接口? - How do I enforce a function type interface on a class method in typescript? 在 typescript 中,如何使用声明的 function 扩展全局接口 - In typescript how do I extend a global interface with a declared function
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM