具有特定类型的动态强制键的通用类型

问题描述 投票:0回答:1

我有一个通用打字稿类型,它接受文本的键名称和值作为通用参数:

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

typescript typescript-generics
1个回答
0
投票

这里的问题是

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
键的对象,那么它将是您期望的更合适的类型。

© www.soinside.com 2019 - 2024. All rights reserved.