Issue
I want to make a Dropdown component with two versions, one that can return multiple selected values and one that returns a single selected value. All of that is determined by a single prop which is called variant. this variant has union type single | multiple. So this is what it looks like:
type MyOption = { label: any; value: any };
type MyDropdownProps =
| {
variant?: "single";
options: [];
onChange: (values: MyOption) => void;
}
| {
variant?: "multi";
options: [];
onChange: (values: MyOption[]) => void;
};
const MyDropdown = (props: MyDropdownProps) => {
return <pre>{JSON.stringify(props)}</pre>;
};
const Render = () => {
return <MyDropdown options={[]} variant="single" onChange={(evt) => {}} />;
};
you see this is work correctly if we specify the variant prop:

my question is what if we don't want to specify the variant prop? what if we already specify it from defaultProps?
const MyDropdown = (props: MyDropdownProps) => {
return <pre>{JSON.stringify(props)}</pre>;
};
MyDropdown.defaultProps = {
variant: "single"
};
You see the onChange is not returning the correct data, it returns with any type. How do we fix this? I've spent weeks trying to find the answer but still have not found it yet :(
Solution
Define your props and component as generic and use the variant type to determine the parameter type for onChange.
Since your variant can only be one of two types, I would opt for a simpler Boolean type determined by the presence of a multiple prop (just like <select>).
interface MyDropDownProps<Multiple extends Boolean> {
multiple?: Multiple;
options: MyOption[];
onChange: (values: Multiple extends true ? MyOption[] : MyOption) => void;
}
You can then define your generic component
const MyDropdown = <Multiple extends Boolean>(
props: MyDropDownProps<Multiple>
) => {
return <pre>{JSON.stringify(props)}</pre>;
};
Answered By - Phil




0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.