Typescript - 为什么不强制按照接口实现?

4

我想知道为什么实现同一个泛型接口,但使用不同的参数时,在派生类中没有强制正确的签名。泛型参数的类型被省略了。

请查看示例:

interface IEvent { id: number; }
interface IHandle<T> {
  handle(event: T): void;
}

class EmailSentEvent implements IEvent {
  constructor(public id: number, public address: string) {}
}

class UserRegisteredEvent implements IEvent {
  constructor(public id: number) {}
}

class MailHandlerState implements 
  IHandle<EmailSentEvent>, 
  IHandle<UserRegisteredEvent> 
{
  // One implementation is enough to satisfy both interfaces
  handle = (event: EmailSentEvent): void => {

  };
}

沙盒

有办法强制实现两个泛型参数吗?谢谢!


似乎是TypeScript编译器的一个错误。我相信它应该要求handle的类型为(event: EmailSentEvent | UserRegisteredEvent): void - emlai
看起来问题更大了,当检查对象属性的类型兼容性时,严格的函数类型并没有被应用。const h: IHandle<UserRegisteredEvent> = { handle(e: EmailSentEvent) { e.address.toString() } };将在运行时崩溃。Playground - Aleksey L.
1
这很奇怪,但在接口中更改为 handle: (event: T) => void; 可以按预期工作。试一下 - Aleksey L.
@AlekseyL。非常好的观察! - Cristian E.
1个回答

2

简述:

为使其可行,请更改 方法 表示法。

interface IHandle<T> {
    handle(event: T): void;
}

转换为带有函数类型的属性

interface IHandle<T> {
    handle: (event: T) => void;
}

Playground

** 在这个具体情况下,仍然可以使用方法语法来实现。


原来这个代码能够按照预期运行:

--strictFunctionTypes 模式中,函数类型参数位置的检查是反变的,而不是双变。严格检查适用于所有函数类型,除了来自方法或构造函数声明的那些函数类型。特别排除了方法,以确保泛型类和接口(例如Array)大多数都是协变关系。严格检查方法的影响将是一个更大的破坏性改变,因为大量的通用类型将变成不变的(即使如此,我们可能会继续探索这种更严格的模式)

来源

也可以在手册中找到相关信息。


2
有趣!即使您以这种方式声明,也不必以这种方式实现,您可以在类中使用方法语法。很好! - T.J. Crowder
哇,那里嵌入了非常有趣的细节! - Cristian E.
2
方法语法示例 - T.J. Crowder
1
感觉有点遗憾,因为它强制执行了一个 catchall 函数 (event: EmailSentEvent | UserRegisteredEvent),这需要使用模式匹配来实现 function per typeof T。但我很高兴编译器至少强制执行了一些类型安全的方式 :))。我猜编译器可以聪明地在将其转换为普通 JS 时映射到一个字典<TType, Action<T>>,同时仍然允许具有相同名称的多个方法/属性函数。非常感谢 @T.J.Crowder - Cristian E.
@CristianE。这是TypeScript中常规的重载语法。制作智能映射并不容易,因为类型在运行时被删除(在编译时被擦除)。 - Aleksey L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接