admin管理员组文章数量:1022720
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.
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.
本文标签:
版权声明:本文标题:javascript - react-select typescript not working properly when I substitute Select with a Component that returns Select - Stack 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745488418a2152851.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论