1

为什么“处理程序”函数变量不可能有多个签名?

以这个理想但无效的代码片段为例:

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;
    }
}

我真正想要的是类似的东西:是一个事件处理程序或一个需要词法绑定handleThing的承诺主体(箭头函数是实现这一点的最简单方法)。其目的是维护多个签名,以便可以根据上下文(即取决于使用它的位置)选择最合适的一个。thenthishandleThing

我也尝试了以下方法,但处理程序变量最终具有 type 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;            
    }
}

仅有handleThing: <T extends object>(a: T | undefined) => object | undefined并不理想:

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

一种选择是使用async函数并取消处理函数变量,但这将违背我的团队为我遇到这种困境的项目建立的既定代码约定。

因此,我问:

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

1 回答 1

1

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

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;
  }
}

一旦您更新到 TypeScript 3.4 或更高版本,第二个代码段将按您预期的方式工作,因为 TypeScript 3.4 为从泛型函数的使用中推断泛型类型添加了更好的支持。在 TypeScript 3.3 或更低版本中,返回值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;
  }
}

如果你让range 超过和,因为(x: undefined) => undefined应该匹配那个签名。 Tobjectundefined

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

于 2019-04-05T01:31:34.193 回答