【问题标题】:TypeScript method OverloadsTypeScript 方法重载
【发布时间】:2020-07-13 21:11:37
【问题描述】:

我有这样的代码,方法有 2 个重载:

/**
 * Returns all keys of object that have specific value:
 * @example
 * KeysOfType<{a:1, b:2, c:1}, 1> == 'a' | 'c'
 */
type KeysOfType<MapT extends Record<string, any>, ValT> = {
    [K in keyof MapT]: MapT[K] extends ValT ? K : never;
}[keyof MapT];

export class Hooks<EventsMap extends Record<string, any>> {
    fireHooks<K extends KeysOfType<EventsMap, void>>(
        event: K,
        context: void,
    ): Promise<void>;

    fireHooks<K extends keyof EventsMap>(
        event: K,
        context: EventsMap[K],
    ): Promise<void>;

    fireHooks<K extends keyof EventsMap>(event: K, context: EventsMap[K]) {
        // ...
    }
}

应该是这样使用的:

type MyHooks = { 
  aaa: void; 
  bbb: { data: string } 
};
let h = new Hooks<MyHooks>();

h.fireHooks('aaa');
h.fireHooks('bbb', { data: 'data' });

有一个泛型类Hooks 带有方法fireHooks,它采用事件名称到上下文数据的映射来验证事件的上下文。 有些事件可以在没有任何上下文的情况下调用,所以我希望这个方法只用一个参数调用这些事件。

一切正常,但问题是这些重载看起来很丑陋而且矫枉过正。

如果我跳过重载,TS 会在 h.fireHooks('aaa'); 上抱怨

Expected 2 arguments, but got 1.ts(2554)

如果我只跳过第二次重载,这似乎是 100% 的实现副本,TS 会在 h.fireHooks('bbb', { data: 'data' }); 上抱怨

Argument of type '"bbb"' is not assignable to parameter of type '"aaa"'.ts(2345)

谁能解释一下

  • 为什么我需要第一次重载才能跳过参数
  • 以及为什么我需要第二次重载,这似乎是多余的,因为它与实现完全相同?

【问题讨论】:

标签: typescript types overloading


【解决方案1】:

“为什么我需要第二次重载,这似乎是多余的,因为它与实现完全一样?”

当您使用重载时,您实际上不能直接调用实现。

观察:

function foo(a: string, b: string): void;
function foo(a: number, b: number): void;
function foo(a: number | string, b: number | string): void {
  //...
}

foo(1, 2) // good
foo('a', 'b') // good
foo(1, 'b') // Error: No overload matches this call.

尽管foo 的实现允许一个参数是数字,另一个是字符串,但重载不允许这样做。

所以你永远不会只有一个重载和一个实现。这些将是相同的。

您要么拥有一个具有一个签名的函数,要么拥有两个或多个重载以及一个实现。


“为什么我需要第一次重载才能跳过参数”

// You can also leave off the argument entirely
fireHooks<K extends KeysOfType<EventsMap, void>>(
    event: K,
): Promise<void>;

因为您有两个函数签名,并且每个函数签名都需要重载,因为(如上所述)您不能直接调用实现。 event 的每个类型都有不同的类型,因为它们对不同的键进行操作。

【讨论】:

  • 谢谢你,@alex-wayne!不过还有后续:> 你也可以完全省略参数 ``` 这个重载签名与其实现签名不兼容。ts(2394) ```
  • 另外,关于第一次重载:在EventsMap 中输入aaa 已经将上下文定义为void。所以当我定义超载时,基本上我会重复自己。所以我希望单独的实现应该允许我对定义为void 的参数使用一个参数,但它没有发生。你知道为什么吗?
猜你喜欢
  • 2015-09-07
  • 2018-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-09
  • 2012-09-23
  • 1970-01-01
相关资源
最近更新 更多