In TypeScript 3.1, I have a generic function with arguments of either (TInput, string)
or (string)
, depending on whether the generic's type parameter TInput extends undefined
. To achieve this, I'm utilizing the new generic rest parameters feature to type the function's args as a conditional type of tuples:
function test (
...args: TInput extends undefined ? [string] : [TInput, string]): void
)
This approach works well, except for one issue. In VSCode, Intellisense reports the parameter names as args_0
and args_1
instead of more human-readable names like input
for the generic parameter (if present) and name
for the string parameter.
I am looking for a way to assign friendlier names to these parameters without sacrificing the accurate Intellisense for parameter count and type(s).
If possible, I would prefer a solution that doesn't rely on tuples but still meets the core requirements: when instantiating the generic function with a specific type, VSCode displays the correct parameter count, names, and types valid for that concrete type.
I attempted adding overloads as shown in the commented code below, but encountered challenges in making them compile successfully. The error received was: Overload signature is not compatible with function implementation. ts(2394)
In a previous version of this sample, I managed to use a type cast to enable overloads compilation. However, this adversely affected Intellisense accuracy for parameter count and types, where two overloads were consistently displayed regardless of the generic type parameter specified.
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>();
Here's a playground link for this code so you can see the problem live.
It's important to note that while reversing the parameter order could simplify the situation, altering the JS-facing signature is not feasible at this point. Additionally, even if parameter order were adjusted, I appreciate how specifying a specific type removes the invalid overload, something which may not be achievable with traditional optional parameters.