在函数类型的成员变量中具有多个函数签名

时间:2019-04-04 22:44:15

标签: typescript typescript-typings typescript-class

为什么不能为“处理程序”功能变量具有多个签名?

以这种理想的方式,但以无效代码段为例:

<textarea id="sendie" maxlength = '100' ></textarea>

我真正想要的是这些东西:class MyEntityService { private handleThing: (a: undefined) => undefined; private handleThing: <T extends object>(a: T) => T; private handleThing: <T extends object>(a: T | undefined) => object | T { if (!a) return undefined; // Various calls to other private methods here return a; } } 是事件处理程序或promise的handleThing主体,需要具有词法then绑定(箭头函数是最简单的方法)以实现这一目标)。目的是this维护多个签名,以便可以根据上下文(即,取决于使用它的位置)来选择最合适的签名。

我也尝试了以下操作,但是处理程序变量最终的类型为handleThing,即所有输入均已有效删除:

any

仅拥有class MyEntityService { private handleThing = this.handleThing_.bind(this); private handleThing_(a: undefined): undefined; private handleThing_<T extends object>(a: T): T; private handleThing_<T extends object>(a: T | undefined): T | undefined { if (!a) return undefined; // Various calls to other private methods here return a; } } 是不理想的:

  1. 它并没有像我需要的那样映射到实际函数的签名,即,当我的输入不是空值时,我的返回类型也肯定不是空值;和
  2. 我在该类中定义的其他一些方法希望提供和接收非null对象,因此上面键入的处理函数并不适用于每个promise或事件处理函数。

一种选择是使用handleThing: <T extends object>(a: T | undefined) => object | undefined函数并取消处理程序函数变量,但这将与我的团队为遇到这个难题的项目所建立的已建立的代码约定相违背。

因此,我问:

  1. 是否有更好的方法来实现我在TypeScript中的处理程序函数变量中保持类型安全的目标?
  2. 有人知道为什么第一个片段不起作用吗?
  3. 第一个代码片段有一天有可能工作(例如,路线图中的联合功能签名选择)吗?

1 个答案:

答案 0 :(得分:1)

要使第一个代码段起作用,您需要将handleThing视为已初始化的属性而不是方法。这意味着您给它一个类型注释和一个值。请注意,重载函数的类型可以表示为每个签名的intersection(例如((x: string)=>number) & ((x: number)=>string)),也可以表示为具有多个bare function signatures的单个对象类型(例如{{ 1}})。像这样:

{ (x: string): number; (x: number): string; }

更新到TypeScript 3.4或更高版本后,第二个代码段将按预期工作,因为TypeScript 3.4添加了对inferring generic types from uses of generic functions的更好支持。在TypeScript 3.3或更低版本中,返回的class MyEntityService { private handleThing: { (a: undefined): undefined; <T extends object>(a: T): T; } = <T extends object>(a: T | undefined) => { if (!a) return undefined; // Various calls to other private methods here return a; } } 将去除所有泛型,并以bind()取代,如您所见。

最后,我不确定为什么不选择一个签名:

any

因为如果您将class MyEntityService { private handleThing = <T extends object | undefined>(a: T): T => { if (!a) return undefined as T; // have to assert here // Various calls to other private methods here return a; } } 设置在(x: undefined) => undefinedT上,则object应该与该签名匹配。

无论如何,希望能有所帮助;祝你好运!