I'v created a generic react component with option elements like this: import * as React from "react";
export interface Option {
value: string;
label: string;
disabled?: boolean;
}
export interface SelectProps<CustomOption extends Option> {
options: CustomOption[];
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
selectedValue: string;
}
export const Select: React.FunctionComponent<SelectProps<Option>> = (props): JSX.Element => {
const options = props.options.map(o => {
return (
<option key={o.value} value={o.value} disabled={o.disabled}>
{o.label}
</option>
);
});
return (
<select onChange={props.onChange} value={props.selectedValue}>
{options}
</select>
);
};
I'm using this like this:
type OptionValues = "FOO" | "BAR" | "BAZ" | "NO_ANSWER";
const createSelect = (selectedOption: OptionValues, onChange: (v: OptionValues) => void): JSX.Element => {
const changeHandler = (event: React.ChangeEvent<HTMLSelectElement>): void => onChange(event.currentTarget.value as OptionValues);
interface SelectOptions extends Option {
value: OptionValues;
}
const selectProps: SelectProps<SelectOptions> = {
onChange: changeHandler,
selectedValue: selectedOption,
options: [
{
value: "FOO",
label: "foo"
},
{
value: "BAR",
label: "bar"
},
{
value: "BAZ",
label: "baz"
},
{
value: "NO_ANSWER",
label: " -- ",
disabled: true
}
]
};
return <Select {...selectProps} />;
};
Is there any way to avoid using type assertion in the changeHandler. event.currentTarget.value as OptionValues
. Also I see that the whole createSelect suddenly is very verbose with references to OptionValues everywhere, but I guess there is no way around it. Alternative ways to solve the problem is also welcomed. That is making sure value is of predetermined types.
In your case you actually need a type-guard, as typescript is not that smart.
If your Select component deep down, is just what I think it is, it will never work.
See typeguards
type OptionValues = 'FOO' | 'BAR' | 'BAZ' | 'NO_ANSWER'
const isOptionValue = (value: unknown): value is OptionValues =>
typeof value === 'string' && ['FOO', 'BAR', 'BAZ', 'NO_ANSWER'].includes(value)
const createSelect = (selectedOption: OptionValues, onChange: (v: OptionValues) => void): JSX.Element => {
const changeHandler = (event: React.ChangeEvent<HTMLSelectElement>): void => {
const value = event.currentTarget.value
if(isOptionValue(value))
onChange(value);
}
...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.