我有一个通用打字稿类型,它接受文本的键名称和值作为通用参数:
type Options<T, TKey, VKey>
其中TKey是文本的键,VKey是值的键。
type Option<
T,
TKey extends PropertyKey,
VKey extends PropertyKey
> = { [key: PropertyKey]: unknown } & { [K in TKey]: string } & { [K in VKey]: T };
type Options<
T = unknown,
TKey extends PropertyKey = "text",
VKey extends PropertyKey = "value"
> = Array<Option<T, TKey, VKey>>;
interface MySelectProps<T> {
value: T;
textProperty: PropertyKey; // Defaults to 'text'
valueProperty: PropertyKey; // Defaults to 'value'
options: Options<T, MySelectProps<T>['textProperty'], MySelectProps<T>['valueProperty']>;
}
let options: Options<string, "label", "value"> = [
{ value: "1", text: "One", label: "test" },
{ value: "2", text: "Two", label: "test" },
];
/*
* Issue here
*/
const myProps: MySelectProps<string> = {
value: "1",
textProperty: "label",
valueProperty: "value",
options: options // Should be valid: textProperty & valueProperty matches Options<string, "label", "value">
}
我无法编写根据传递给
options
和 textProperty
的值正确验证
valueProperty
的类型
这是一个用于轻松测试的打字稿游乐场Playground
这里的问题是
textProperty
界面中 valueProperty
和 MySelectProps
的类型与您传递的 options
不一致:Options<string, "label", "value">
。
textProperty
和 valueProperty
都是 PropertyKey
类型,即 string | number | symbol
,而您为这些字段传递 exact 值:“标签”和“值”。虽然它们是字符串,但编译器将确切的值和字符串视为不同的类型(请参阅文字类型)。您可以通过在第 20 行声明 Options<string, PropertyKey, PropertyKey>
来修复它。
这是修改后的代码,没有上面建议的 hack:
type Option<
T,
TKey extends PropertyKey,
VKey extends PropertyKey
> = { [key: string]: unknown } & { [K in TKey]: string } & { [K in VKey]: T };
type Options<
T = unknown,
TKey extends PropertyKey = "text",
VKey extends PropertyKey = "value"
> = Option<T, TKey, VKey>[];
type MySelectProps<T, TKey extends PropertyKey = "text", VKey extends PropertyKey = "value"> = {
value: T;
textProperty: TKey; // Defaults to 'text'
valueProperty: VKey; // Defaults to 'value'
options: Options<T, TKey, VKey>;
}
let options: Options<string, "label", "value"> = [
{ value: "1", label: "One" },
{ value: "2", label: "Two" },
{ value: "3", label: "Three" },
{ value: "4", label: "Four" },
{ value: "5", label: "Five" },
{ value: "6", label: "Six" }
];
const myProps: MySelectProps<string, "label", "value"> = {
value: "1",
textProperty: "label",
valueProperty: "value",
options,
}
这有点不方便,因为你需要多次指定“标签”和“值”,但你可以这样做:
type TKey = "label";
type VKey = "value";
let options: Options<string, TKey, VKey> = [
{ value: "1", label: "One" },
{ value: "2", label: "Two" },
{ value: "3", label: "Three" },
{ value: "4", label: "Four" },
{ value: "5", label: "Five" },
{ value: "6", label: "Six" }
];
const myProps: MySelectProps<string, TKey, VKey> = {
value: "1",
textProperty: "label",
valueProperty: "value",
options,
}
您可能还想将
PropertyKey
替换为 string
,因为如果 Option
不是可以具有 symbol
或 number
键的对象,那么它将是您期望的更合适的类型。