New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
react-select: Select.onChange typings wrong (?) #32553
Comments
I found this entirely confusing.
_onTagChange(
value: ReactSelectTypes.ValueType<{value: number; label: string}>,
action: ReactSelectTypes.ActionMeta
) {
console.log('l68:', value, ' action:', action);
switch(action.action) {
case 'pop-value':
case 'remove-value':
}
if (value && value.length > 0) {
e let firstOption = value[0]; // Errors here with: Element implicitly has an 'any' type because type '{ value: number; label: string; } | { value: number; label: string; }[]' has no index signature.
}
// this.setState({ categoryTags: tags });
} |
The first argument of the See JedWatson/react-select#2902 for a more in-depth discussion about the onChange handler in combination with TypeScript. |
@rvanlaarhoven -- Updated OP to accept single or array. IMO an array should be passed to the handler regardless of whether or not the select |
I agree with @JoshMcCullough |
The biggest annoyance for me is that an array or single value is returned depending on the value of Could we do some sort of unioning or conditional typing to resolve this? (warning: untested ideas) interface BaseProps<OptionType extends OptionTypeBase = { label: string; value: string }> extends SelectComponentsProps {
... /* all existing fields except isMulti and onChange */
}
interface SingleValueProps<...> extends BaseProps<...> {
isMulti: false;
onChange: (value: OptionType | null | undefined, action: ActionMeta) => void;
}
interface MultiValueProps<...> extends BaseProps<...> {
isMulti: true;
onChange: (value: OptionsType<OptionType> | null | undefined, action: ActionMeta) => void;
}
/* where the props are defined */
selectProps: SingleValueProps<...> | MultiValueProps<...> or perhaps interface Props<IsMulti extends boolean, OptionType extends OptionTypeBase = { label: string; value: string }> extends SelectComponentsProps {
...
isMulti: IsMulti,
onChange: (value: ValueType<IsMulti, OptionType>, action: ActionMeta) => void;
...
}
export type ValueType<IsMulti extends boolean, OptionType extends OptionTypeBase> =
(IsMulti extends false ? OptionType : OptionsType<OptionType>) | null | undefined; EDIT: after thinking about this some more, the type is inferrable if you hard-code |
I used a type assertion as a workaround here:
|
Is an interface (Typescript) available for the multi value |
@hoetmaaiers You could make a helper: type Nullable<T> = T | null | undefined; |
As a workaround, I defined an interface: And then, casted the parameter: |
using
without using |
I'm still having this issue and it's really annoying to do on every onChange (because I'm not using any multi select) the cast to the single option type.... Every time i must use item => (item as OptionTypeBase).value. Really bad. |
Indeed. The typing should be smart enough to determine whether it is an array (if |
Update, having to use multiple components and the above issue was bothersome. So I combined them all into a single Select component, isMulti is now a required prop so it knows the type of value and onChange. import ReactSelect, { ActionMeta, OptionTypeBase, Props } from 'react-select';
import AsyncSelect, { AsyncProps } from 'react-select/async';
import Creatable, { CreatableProps } from 'react-select/creatable';
// We use a generic param P here since directly omitting from a interface with generic params doesn't work
type IGenericSelectProps<OptionType, P = Props<OptionType>> =
Omit<P, 'value' | 'onChange' | 'isMulti'>
& Partial<AsyncProps<OptionType>>
& Partial<CreatableProps<OptionType>>
& {
isMulti: boolean;
}
interface ISingleSelectProps<OptionType> extends IGenericSelectProps<OptionType> {
value: OptionType | null | undefined;
onChange?: (option: OptionType | null | undefined, action: ActionMeta<OptionType>) => void;
isMulti: false;
}
interface IMultiSelectProps<OptionType> extends IGenericSelectProps<OptionType> {
value: OptionType[];
onChange?: (option: OptionType[], action: ActionMeta<OptionType>) => void;
isMulti: true;
}
type ISelectProps<OptionType> = ISingleSelectProps<OptionType> | IMultiSelectProps<OptionType>;
const Select = <OptionType extends OptionTypeBase = { label: string; value: string }>(props: ISelectProps<OptionType>) => {
// Use correct react-select component based on props
let Component: ComponentType<ISelectProps<OptionType>> = ReactSelect as any;
if (props.loadOptions && props.onCreateOption) {
Component = AsyncCreatable as any;
} else if (props.loadOptions) {
Component = AsyncSelect as any;
} else if (props.onCreateOption) {
Component = Creatable as any;
}
return <Component {...props}/>;
}; |
any news on this? |
1 similar comment
any news on this? |
DefinitelyTyped/types/react-select/lib/Select.d.ts
Line 166 in 6f8151b
I believe this should be defined as:
When an option is selected, the raw option object is sent, not the
ValueType
of that object.The text was updated successfully, but these errors were encountered: