feat: make wrapMenuList generic
This makes the wrapMenuList function generic.
Currently wrapping custom components with wrapMenuList is quite difficult in TypeScript, as it almost always requires type casting. It neither accepts a generic MenuList component, nor returns one that is suitable for SelectComponentsConfig. This is evident from the code in this repository, too, as the returned components object needed a type cast before.
By making the function generic and return a generic component, no type casts are necessary on the outside. There are still some required here internally in two places:
- the
innerRefprop signature does not match with what react-select itself uses, but this should be fine, as React really allows both signatures. - in tests, the props object is not a full props object, now that it extends
MenuListProps, but for testing purposes it should not matter either.
Hello. Thanks for your work. I'm working now with improvement of typings in feature/mocks_in_tests branch. I'll consider your PR after finish.
Cheers, there seems to be something similar in there indeed, let's see if it resolves all issues. Is there an ETA on when that might land?
I'll try to finish this week.
Hello. Sorry for the long wait. Check please new version.
Hi @vtaits, no worries about the wait. I tested your changes out, the function still did not want to accept a generic component - for that, the function itself needs to be generic. I updated my branch with the necessary changes - does this seem fine to you?
Hey @vtaits, pinging again - can we proceed with this in some way, or should I change anything?
Hello. MenuList in react-select is generic. So the result of wrapMenuList function should be a generic component. In your changes wrapMenuList is generic, but its result isn't.
https://github.com/JedWatson/react-select/blob/master/packages/react-select/src/components/Menu.tsx#L436
Can you describe the task you're solving?
I have a custom generic MenuList component that I'm trying to pass into wrapMenuList without any type casting.
export const MenuList = <Option extends SelectOptionType, IsMulti extends false, Group extends GroupBase<Option>>(
props: MenuListProps<Option, IsMulti, Group>,
) => {
return <components.MenuList {...props} />;
};
I don't understand your point about the result not being generic - in my testing, it does return a generic component, as expected, because the returned WrappedMenuList component uses the same generic props args from wrapMenuList.
Here's what I see in my editor after the changes, wrapMenuList seems to infer the correct return type from the passed component:

@mihkeleidast
It will work if you make type of MenuList the same as components.MenuList:
export const MenuList = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>(
props: MenuListProps<Option, IsMulti, Group>,
) => {
return <components.MenuList {...props} />;
};
https://github.com/JedWatson/react-select/blob/3aee85cb8c5d045d47d45b0f9ebd0c58d4593c42/packages/react-select/src/components/Menu.tsx#L436
@vtaits but I don't want to use the defaults - the whole point of generics is so those arguments could be customized, isn't it? The code example I provided above removed the custom code inside the component that needs those customized arguments to work properly. I did not think it was necessary to show all of my complex code, as the issue is only with generics.
I didn't notice that react-select accepts your format of function.
I tried to do something more generic like
function wrapMenuList<T>(MenuList: T): T {}
But there were other problems.
Your changes are published in version 0.7.1.
Cheers, thanks for merging!