Cannot narrow arguments of overloaded function
The API of a UI library uses overloaded functions to add controls, like this.
// *.d.ts
declare function add(type: "scrollbar", name: string): Scrollbar
declare function add(type: "slider", name: string): Slider
// ...
I want to encapsulate that function for ease of use.
Define a type to associate the control name with the control type.
type Control<T> = T extends "scrollbar" ? Scrollbar :
T extends "slider" ? Slider : never;
Other controls are temporarily ignored.
Then define a generic function.
function myAdd<T extends "scrollbar" | "slider">(type: T, name: string, /* other arguments */): Control<T> {
// typeof type is "scrollbar" | "slider"
const control = add(type, name); // Error description is below
^^^^
// and typeof control now is Scrollbar & Slider, expect Scrollbar | Slider
return control as Control<T>;
}
No overload matches this call.
Overload 1 of 2, '(type: "scrollbar", name: string): Scrollbar', gave the following error.
Argument of type '"scrollbar" | "slider"' is not assignable to parameter of type '"scrollbar"'.
Type '"slider"' is not assignable to type '"scrollbar"'.
Overload 2 of 2, '(type: "slider", name: string): Slider', gave the following error.
Argument of type '"scrollbar" | "slider"' is not assignable to parameter of type '"slider"'.
Type '"scrollbar"' is not assignable to type '"slider"'.ts(2769)
I think I've written something incorrectly that makes it impossible to infer the type correctly. How should I modify it?
This is working as intended. The overload only allows to either pass a "scrollbar" type, or a "slider" type. The generic version additionally allows to pass the "scrollbar" | "slider" type.
On a separate note, please don't use the "types not correct with/in callback" issue template for issues unrelated to #9998. Use of that template is why your issues keep getting marked as duplicates.
How can I overwrite it to make it work? Can I only narrow the type one by one?
if (type === "scrollbar")
add(type, name);
else if (type === "slider")
add(type, name);
else if // ...
On a separate note, please don't use the "types not correct with/in callback" issue template for issues unrelated to https://github.com/microsoft/TypeScript/issues/9998. Use of that template is why your issues keep getting marked as duplicates.
I see.
It would be better to have the types like this:
type ControlTypes = {
scrollbar: Scrollbar,
slider: Slider
};
type Control<T extends keyof ControlTypes> = ControlTypes[T];
in which case add could be declared as:
declare function add<T extends keyof ControlTypes>(type: T, name: string): Control<T>
and then your generic implementation of myAdd would likely work more smoothly.
Thanks a lot!