参数为条件元组类型时,重载参数的智能感知命名

时间:2019-02-20 22:24:37

标签: typescript typescript-generics

在TypeScript 3.1中,我有一个泛型函数,其参数为(TInput, string)(string),具体取决于泛型的类型参数TInput extends undefined。目前,我正在使用新的generic rest parameters功能来将函数的args输入为元组的条件类型:

function test (
    ...args: TInput extends undefined ? [string] : [TInput, string]): void
)

这几乎完美。当我用具体类型实例化泛型函数时,VSCode仅向我显示适用于该泛型类型的重载。是的!

但是有一个问题:VSCode中的Intellisense将参数名称报告为args_0args_1,而不是诸如input这样更易理解的通用参数名称(如果存在),并且name表示字符串参数。

是否可以在不丢失参数计数和类型的(正确)Intellisense的情况下,在这些参数上附加更友好的名称?

顺便说一句,我可以使用不使用元组的解决方案,只要核心需求可以正常工作,那就是:当泛型函数使用实型实例化并且将鼠标悬停在VSCode中时,我查看适用于该具体类型的正确参数计数,名称和类型。

我尝试添加重载(请参见下面的注释代码),但无法弄清楚如何获取重载进行编译。我得到:重载签名与函数实现不兼容。 ts(2394)

在此示例的早期迭代中,我能够使用类型强制转换来获取重载进行编译,但这反过来又破坏了Intellisense的参数计数和类型,其中“中断”表示(与下面的代码不同)两个重载总是显示在Intellisense中,即使泛型类型参数应该将列表缩小为一个有效的重载。

const makeTest = <TInput>() => {
//  Adding the overloads below doesn't work as expected. There are two problems: 
//    1. compiler error: "Overload signature is not compatible with function implementation. ts(2394)"
//    2. if I use a cast to get around the compile error, both overloads show in Intellisense regardless of TInput
//  function test (name: string): void; 
//  function test (input: TInput, name: string): void;
    function test (...args: TInput extends undefined ? [string] : [TInput, string]): void {
        // do stuff
    }
    return test;
}

// type inferred as: const f1: (args_0: string) => void
const f1 = makeTest<undefined>(); 

// type inferred as: const f2: (args_0: number, args_1: string) => void
const f2 = makeTest<number>();

此代码为playground link,因此您可以实时查看问题。

顺便说一句,我知道我可以通过反转参数顺序来简化此操作,但是更改其面向JS的签名并不现实。我现在只能更改TS的类型。另外,即使参数被反转了,我真的很喜欢用特定类型实例化泛型将如何消除无效的重载,而且我不知道这是否适用于传统的可选参数。

1 个答案:

答案 0 :(得分:1)

我只是将函数断言为依赖于TInput的条件类型,这将为您提供所需的更好的智能感知。您很难在rest参数中为元组指定参数名称:

const makeTest = <TInput>() => {

    function test (...args: [string] | [TInput, string]): void {
        // do stuff
    }
    return test as (TInput extends undefined ? ((name:string) => void) : ((input: TInput, name: string) => void);
}

或带有makeTest的实现和公共签名的版本:

function makeTest<TInput>(): (TInput extends undefined ? ((name: string) => void) : ((input: TInput, name: string) => void))
function makeTest<TInput>(): ((name: string) => void) | ((input: TInput, name: string) => void) {

    function test(...args: [string] | [TInput, string]): void {
        // do stuff
    }
    return test;
}