具有重载的可调用接口

Invokable interfaces with overloads

我有多种类型要与(外部)函数相关联。我决定将它们保存在幕后数组中,如下所示:

var labelGenerators : ILabelGenerator[] = []

其中 ILabelGenerator 应该是类型可以具有的不同形状的通用接口,例如:

interface ILabelGenerator{
  (container : SomeContainerObject, delta: IDeltaValues): string;
  (container : SomeContainerObject, x: number, y: number): string;
  (container : SomeContainerObject, x: Date, y: number): string;
}

现在,我不知道如何向 labelGenerators 数组添加一个项目,因为如果我这样做:

labelGenerators[0] = (container:SomeContainerObject, x:number, y: number) => {
   return "label 0"; //the real code uses the parameters
}

我收到类型 (container:SomeContainerObject, x:number, y: number) => string is not assignable to type ILabelGenerator 错误。

如何解决这个问题? (我使用的是 TypeScript 1.3,但由于我有大约 10 种调用形式,因此 1.4 联合类型将非常笨重)

因为第二个参数需要与所有签名兼容。使用 x:any

这应该可以避免编译器错误,因为您明确告诉 TS:

labelGenerators[0] = <ILabelGenerator>(
     (container: SomeContainerObject, x: number, y: number) => { 
         return "label 0"; //the real code uses the parameters 
     });

您的原始接口没有说 "it can be any of these",它说 "it will be compatible with all of these" - 以满足您必须使用扩展类型或实现所有适当的重载。

您想要的界面是"it will be one of these"。在这种情况下,您实际上应该创建包含实际合同的接口。实现在契约中唯一承诺的是第一个参数的类型为 SomeContainerObject。就附加参数而言,一切皆有可能。

合同的存在是为了让调用代码知道它可以依赖什么。因此,我会使用以下接口:

interface ILabelGenerator{
  (container: SomeContainerObject, ...additional: any[]): string;
}

使用此接口的原因是,这就是您对 ILabelGenerator.

实现的全部承诺

例如,当您键入以下内容时...

labelGenerators[0](

你会真实地反映现实。

您的原始界面承诺过度,因为它建议 "you can call your preferred signature"。这个版本说 "I have no idea what you should supply after your first argument"。也就是说,这是事实!