I want to define a function that can only be called with a specific combination of parameters and to get proper autocompletion for each parameter. A simplified example is this:
interface MyFunction {
(key: "one"): void;
(key: "two", param: Record<"paramForTwo",string>): void;
(key: "three", param: Record<"paramForThree", string>): void;
}
const t: MyFunction = () => { /* implementation is not relevant */ };
This correctly allows
fn("one");
fn("two", { "paramForTwo": "a"})
fn("three", { "paramForThree": "b"})
and rejects
fn("two", { "paramForThree": "c"})
However, in the auto-completion for both WebStorm and VSCode, when I enter
fn("three", "
I get suggestions for both paramForTwo
and paramForThree
.
Even worse, the error message enumerates all possible overloads
error TS2769: No overload matches this call.
Overload 1 of 3, '(key: "two", param: Record<"paramForTwo", string>): void', gave the following error.
Argument of type '"three"' is not assignable to parameter of type '"two"'.
Overload 2 of 3, '(key: "three", param: Record<"paramForThree", string>): void', gave the following error.
Object literal may only specify known properties, and '"paramForTwo"' does not exist in type 'Record<"paramForThree", string>'.
When there are more overloads, the error message does not count all of the, just the last.
I have also tried define types like the addEventListener
types in the DOM library:
interface MyParams {
"one": never,
"two": "paramForTwo",
"three": "paramForThree",
}
function fn<T extends keyof MyParams>(key: T, param: Record<MyParams[T], string>) {}
With this approach, I get proper autocompetion
and the error message is much better:
fn("two", { "paramForThree": "b" })
now shows
error TS2353: Object literal may only specify known properties, and '"paramForThree"' does not exist in type 'Record<"paramForTwo", string>'
But now
fn("one");
also shows an error, because the second parameter is missing. Is there any way to define the function such that it accepts all variants for MyFunction
and computes auto-completion based on the first parameter like in my second approach?
1