TypeScript 函数重载。 IDE 参数类型混淆

TypeScript function overloading. IDE argument type confusion

我正在尝试为我的 TypeScript API 获得良好的开发人员体验,但我遇到了意想不到的问题。 如下所示重载函数时:

/** Comment 1 */
function a(key: 'key1', args: { arg1: number }): string
/** Comment 2 */
function a(key: 'key2', args: { arg2: number }): string
function a(key: string, args) { }

当有人试图在 IDE 中调用该函数时(我尝试了 VSCode 和 WebStorm)

a('key2', { })
//         ^

IDE 基于第二种联合建议对象 属性。 (在本例中为 arg1arg2

我希望它的行为类似于此代码:

/** Comment 1 */
function a(key: 'key1'): (args: { arg1: number }) => string
/** Comment 2 */
function a(key: 'key2'): (args: { arg2: number }) => string
function a(key: string, args) { }

调用时在哪里

a('key2')({ })
//         ^

只显示需要的属性。

是否有可能在第一种情况下得到相同的行为?

这是一个常见问题 - 例如在事件侦听器上下文中 - 我最近自己也遇到过。幸运的是,有一个简单而优雅的解决方案。

首先,在你的问题中有两种略有不同的表述方式;一次,您要正确键入的对象是 a 的另一个参数,一次是您要从 a return 的函数的单数参数。以下解决方案应该适用于两个版本,但我将在第一种情况下展示它,这种情况应该更常见。

主要技巧是避免重载并用单个泛型替换它们;这也使得处理 a 和打字变得更加容易。据我所知,在您描述的情况下,这应该总是可行的。

第 1 步通过接口定义函数signatures/overloads

interface Signatures {
    key1: {arg1: number};
    key2: {arg2: number};
}

当然,如果参数超过2个,那就有点困难了;但是出现上述问题的典型场景通常恰好有 2 个参数 - 一个键和一个值。

步骤 2:定义单个函数泛型函数签名:

function a<K extends keyof Signatures>(key: K, args: Signatures[K]): string {
    return 'hello world'; // TODO
}

然后,当您调用 a('key1', ) 时,args 会自动推断为 {arg1: number}.

类型