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 :(
CodePudding user response:
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>;
};
CodePudding user response:
Consider this example:
import React from 'react'
type MyOption = { label: any; value: any };
type MyDropdownProps =
{
options: [];
onChange: (values: MyOption[] | MyOption) => void;
};
const MyDropdown = (props: MyDropdownProps) => {
return <pre>{JSON.stringify(props)}</pre>;
};
const Render = () => {
return <MyDropdown options={[]} onChange={(evt /* MyOption[] | MyOption */) => { }} />;
};
If you don't want to specify variant
property, then, in fact you don't need a union of props. You need a union of onChange
arguments