So instead of using Select directly I thought it would be better to create a ponent named CustomSelect which will return Select with some properties prefilled.
The issue is that now when I use the CustomSelect ponent with property isMulti={false}
typescript does not automatically understands that OnChange
property should be of type
(newValue: SingleValue<IOption>, actionMeta: ActionMeta<IOption>) => void
instead of
(newValue: SingleValue<IOption> | MultiValue<IOption>, actionMeta: ActionMeta<IOption>) => void
Why is this happening and is there any good workaround?
CustomSelect.tsx
import Select, {
ponents,
OptionProps,
ValueContainerProps,
Props as SelectProps,
} from "react-select";
import { IOption } from "../../Table/Types";
import "./CustomSelect.scss";
//type IOption = {
// value: any;
// label: string;
// icon?: string;
//};
const { Option: OptionCointainer, ValueContainer } = ponents;
function OptionWithIcon(props: OptionProps<IOption>) {
const {
label,
data: { icon },
} = props;
return (
<OptionCointainer {...props} className="selectOption">
{!!icon && <img src={icon} alt={label} />}
{label}
</OptionCointainer>
);
}
// react-select is buggy when you try to override rendered value ponent
// children is being used as a workaround
function ValueWithIcon(props: ValueContainerProps<IOption>) {
const { getValue, children } = props;
const { label, icon } = getValue()[0];
return (
<ValueContainer {...props} className="selectValue">
<>
{!!icon && <img src={icon} alt={label} />}
{label}
<span className="hiddenAbsolute">{children}</span>
</>
</ValueContainer>
);
}
function CustomSelect(props: SelectProps<IOption>) {
const { options } = props;
return (
<Select
isDisabled={options ? options.length < 2 : true}
ponents={{
Option: OptionWithIcon,
ValueContainer: ValueWithIcon,
}}
{...props}
/>
);
}
export default CustomSelect;
Filters.tsx
<Select
id="currencyFrom"
isMulti={false}
value={state.fromCurrency}
// if I hover on change type is (newValue: SingleValue<IOption>, actionMeta: ActionMeta<IOption>) => void
onChange={onValueChange("fromCurrency")}
options={someOptions}
isSearchable={false}
/>
<CustomSelect
id="currencyTo"
isMulti={false}
value={state.toCurrency}
// if I hover on change type is (newValue: SingleValue<IOption> | MultiValue<IOption>, actionMeta: ActionMeta<IOption>) => void
onChange={onValueChange("toCurrency")}
options={someOptions}
isSearchable={false}
/>
So instead of using Select directly I thought it would be better to create a ponent named CustomSelect which will return Select with some properties prefilled.
The issue is that now when I use the CustomSelect ponent with property isMulti={false}
typescript does not automatically understands that OnChange
property should be of type
(newValue: SingleValue<IOption>, actionMeta: ActionMeta<IOption>) => void
instead of
(newValue: SingleValue<IOption> | MultiValue<IOption>, actionMeta: ActionMeta<IOption>) => void
Why is this happening and is there any good workaround?
CustomSelect.tsx
import Select, {
ponents,
OptionProps,
ValueContainerProps,
Props as SelectProps,
} from "react-select";
import { IOption } from "../../Table/Types";
import "./CustomSelect.scss";
//type IOption = {
// value: any;
// label: string;
// icon?: string;
//};
const { Option: OptionCointainer, ValueContainer } = ponents;
function OptionWithIcon(props: OptionProps<IOption>) {
const {
label,
data: { icon },
} = props;
return (
<OptionCointainer {...props} className="selectOption">
{!!icon && <img src={icon} alt={label} />}
{label}
</OptionCointainer>
);
}
// react-select is buggy when you try to override rendered value ponent
// children is being used as a workaround
function ValueWithIcon(props: ValueContainerProps<IOption>) {
const { getValue, children } = props;
const { label, icon } = getValue()[0];
return (
<ValueContainer {...props} className="selectValue">
<>
{!!icon && <img src={icon} alt={label} />}
{label}
<span className="hiddenAbsolute">{children}</span>
</>
</ValueContainer>
);
}
function CustomSelect(props: SelectProps<IOption>) {
const { options } = props;
return (
<Select
isDisabled={options ? options.length < 2 : true}
ponents={{
Option: OptionWithIcon,
ValueContainer: ValueWithIcon,
}}
{...props}
/>
);
}
export default CustomSelect;
Filters.tsx
<Select
id="currencyFrom"
isMulti={false}
value={state.fromCurrency}
// if I hover on change type is (newValue: SingleValue<IOption>, actionMeta: ActionMeta<IOption>) => void
onChange={onValueChange("fromCurrency")}
options={someOptions}
isSearchable={false}
/>
<CustomSelect
id="currencyTo"
isMulti={false}
value={state.toCurrency}
// if I hover on change type is (newValue: SingleValue<IOption> | MultiValue<IOption>, actionMeta: ActionMeta<IOption>) => void
onChange={onValueChange("toCurrency")}
options={someOptions}
isSearchable={false}
/>
Share
Improve this question
edited Sep 11, 2022 at 18:34
prof chaos
asked Sep 11, 2022 at 11:00
prof chaosprof chaos
4444 silver badges20 bronze badges
1 Answer
Reset to default 5The SelectProps
type you are trying to adapt is a generic type with 3 type arguments (defined here). Because you provide a type for the first argument, inference is disabled the other 2 arguments and Typescript sets them to their default values instead.
If you need inference to work, you cannot provide partial type arguments, I can see 2 solutions:
- Get rid of the
Option
argument inSelectProps<Option>
and let theOption
type be inferred as well
function CustomSelect(props: SelectProps) {
- If you need to enforce a specific
Option
type, create another generic type for your props that only takes the 2 last arguments and let typescript infer these:
type CustomSelectProps<
IsMulti extends boolean = boolean,
Group extends GroupBase<Option> = GroupBase<Option>
> = SelectProps<Option, IsMulti, Group>;
…
function CustomSelect(props: CustomSelectProps) {
Also, because you want this type of inference to happen when using the ponent, you should also make your ponent generic, applying the same logic to the StateManagedSelect
ponent type (defined here).
This gives us the following ponent type definition, using the CustomSelectProps
:
function CustomSelect<
IsMulti extends boolean = false,
Group extends GroupBase<IOption> = GroupBase<IOption>
>(props: SelectProps<IOption, IsMulti, Group>) {
Updated codesandbox: you'll see I had to apply the same logic to your other ponents as well, as all the types depend on each other.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745488421a4629875.html
评论列表(0条)