在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_0
和args_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的类型。另外,即使参数被反转了,我真的很喜欢用特定类型实例化泛型将如何消除无效的重载,而且我不知道这是否适用于传统的可选参数。
答案 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;
}