我有一个名为 Select 的组件,它有 options
、value
和 onChange
属性。 options
是具有标签和值属性的对象数组。
这是我的 Select.tsx 代码
import * as React from "react";
import type { ChangeEventHandler, ReactElement } from "react";
export interface OptionType {
value: string | number | null;
label: string;
}
export const Select = ({
value,
onChange,
options
}: {
value: string | number | null;
onChange: ChangeEventHandler<HTMLSelectElement>;
options: OptionType[];
}): ReactElement => (
<select value={value ?? ""} onChange={onChange}>
{options.map((option) => (
<option value={option.value ?? ""} key={option.value}>
{option.label}
</option>
))}
</select>
);
我像这样使用了 Select 组件,问题出在下面的 onChange 事件处理程序上。我希望 event.target.value 具有 UnitType 类型。
import * as React from "react";
import { Select } from "./Select";
const { useState } = React;
type UnitType = "cm" | "m" | "km";
interface UnitOptionType {
label: string;
value: UnitType;
}
// Select options array with a custom type
const timeOptions: UnitOptionType[] = [
{ label: "Centimeter", value: "cm" },
{ label: "Meter", value: "m" },
{ label: "Kilometre", value: "km" }
];
export const App = () => {
const [value, setValue] = useState<UnitType | null>(null);
return (
<div>
<Select
options={timeOptions}
value={value}
onChange={(event) => {
// I WANT this to have the type of UnitType
// but it is string
setValue(event.target.value)
}}
/>
</div>
);
};
您可以在此 Codesandbox 链接上查看我的代码:
https://codesandbox.io/s/xenodochial-matan-i3p9z?file=/src/App.tsx:0-765
最佳答案
value
的 HTMLSelectElement
始终是 string
。它在 TypeScript 附带的 lib.dom
标准类型库中以这种方式键入。您无能为力改变这一点。
在本例中,我将使 <Select>
组件变得通用,以便它知道其选项的类型。
然后让 onChange
回调接收该类型,而不是整个事件。
最后,您将值转换为该类型,因为您的值将是选项之一的值。
把它们放在一起你会得到:
export interface OptionType<T extends string | number | null> {
value: T;
label: string;
}
export const Select = <T extends string | number | null>({
value,
onChange,
options
}: {
value: T;
onChange: (newValue: T) => void;
options: OptionType<T>[];
}): ReactElement => (
<select value={value ?? ""} onChange={(event) => onChange(event.target.value as T)}>
{options.map((option) => (
<option value={option.value ?? ""} key={option.value}>
{option.label}
</option>
))}
</select>
);
现在 onChange
提供 T
,这意味着选项值的并集,因此您可以将该值直接传递给 setState
,而无需通过事件对象进行代理。
<Select
options={timeOptions}
value={value}
onChange={setValue}
/>
Typescript playground with the above code and no type errors.
最后一点:您使用值的类型为 string | number | null
,但如上所述, .value
将始终返回一个字符串,因此您永远不会从中得到 null
或 number
。因此,支持这些类型将会更加复杂,并且您无法单独在 typeland 中完成它,因为您需要知道如何在运行时将 string
转换为您想要的类型。
关于reactjs - 如何输入 html select 元素,以便 event.target.value 引用选项值类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68896793/