我现在为此苦苦挣扎了一段时间。
我想创建一个 React 选择组件,其中 TS 可以从一组选项值中推断组件的值类型。
比方说:
const myFakeValueSet = [
"dc9d15ee-7794-470e-9dcf-a8d1dd1a6fcf",
"1bda4f79-a199-40ce-985b-fa217809d568",
"e91b2cac-48f6-4d60-b86f-ece02f076837",
"66a9d7ac-9b25-4e52-9de3-4b7238135b39"
] as const;
const optionsWithTypedValues: Option<typeof myFakeValueSet[number]>[] = myFakeValueSet.map((fakeValue) => ({
value: fakeValue,
label: fakeValue
}));
const MyComponent = <Select
options={optionsWithTypedValues}
value={"something"} // should throw TS error
/>;
这是一个有效的实现:
type OptionValue = typeof myFakeValueSet[number];
type Option<Type extends OptionValue> = {
value: Type;
label: string;
};
type SelectProps<Type extends OptionValue> = {
options: Option<Type>[];
value: Type;
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void;
};
function Select<Type extends OptionValue>({ options, value, onChange }: SelectProps<Type>) {
return (
<select value={value} onChange={onChange}>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
);
}
但是如您所见,我必须从非泛型的
T
扩展泛型OptionValue
。所以我尝试从选择默认值 string | number | readonly string[] | undefined
进行扩展,但是如果我这样做,当我为我的组件提供意外值(例如 "something"
)时,它不会抛出错误,并且会更改类型到原来的T联合+"something"
。这就像 TS 从选项的值和value
(实际上是defaultValue
)推断类型。
我试图让它完全通用,所以 TS 会知道我只能从我给他的选项集中为 Select 组件设置一个值。
有可能吗?
原始示例:https://codesandbox.io/s/react-typescript-forked-g34stp
你只需要做一点小改动,它就会按照你想要的方式工作。基本上,您需要告诉 TS,这些值只能是
myFakeValueSet
中的值。对不对,typeof myFakeValueSet
是string[]
。您需要告诉 TS 将其视为不可变数组。你可以用const myFakeValueSet = [...] as const
来做到这一点。这样会导致TS在你通过的时候报错value={"something"}