我有一个键数组和一个值类型元组。
const keys = ["name", "age", "isAlive"] as const;
type Values = [string, number, boolean];
如何使用它们动态构造以下类型?
type DesiredType = {
name: string;
age: number;
isAlive: boolean;
}
我已经尝试过:
const keys = ["name", "age", "isAlive"] as const;
type Values = [string, number, boolean];
type ObjFromArrays<T extends readonly string[], K extends any[]> = {
[index in T[number]]: K[number];
};
type DesiredType = ObjFromArrays<typeof keys, Values>;
但是它不起作用,因为它在
T
上迭代,但不在 K
上迭代。
本质上,您希望
ObjFromArrays<K, V>
采用相同形状的两种数据类型,其中第一个 K
保存键,第二个 V
保存值,并且您希望将它们连接到单个对象类型中,其中每个键与每个值配对。实现此操作的方法是在 I
数据类型的相关索引 K
上编写 映射类型,并使用 键重新映射 将
K[I]
用作键,并将 V[I]
用作值。 假设 K
是一个 tuple 类型,那么相关索引就是 K
对应于元组中位置的类似数字的字符串键。也就是说,如果 K
看起来像 ["name", "age", "isAlive"]
,那么我们要迭代的索引就是 "0" | "1" | "2"
。
我们的实现方式如下:
type ObjFromArrays<
K extends readonly string[],
V extends Record<keyof K, any>
> = {
[I in `${number}` & keyof K as K[I]]: V[I];
};
这里
K
已被 constrained 为(只读)字符串数组,而 V
已被限制为与 K
具有相同的索引。您也可以写 V extends readonly string[]
,但是您需要在实现内部检查
I
的每个索引
K
也是
V
的有效索引,如果不是,则执行某些操作。 我们希望防止
["name", "age", "isAlive"]
出现
K
以及
[string]
出现
V
之类的情况,其中索引不匹配。相反,通过限制
Record<keyof K, any>
,我们基本上要求
V
至少具有与
K
相同的索引。映射类型迭代
K
(
keyof K
) 的键,这些键也是 (
&
) 类似数字的字符串。 (
`${number}`
)。我与
`${number}`
相交的原因是为了避免迭代所有类似数组类型的明显键,例如
"length"
和
"reduce"
和
"forEach"
等。对于每个这样的键
I
,键输出类型为
K[I]
,值为
V[I]
。让我们测试一下:
const keys = ["name", "age", "isAlive"] as const;
type Values = [string, number, boolean];
type DesiredType = ObjFromArrays<typeof keys, Values>;
/* type DesiredType = {
name: string;
age: number;
isAlive: boolean;
} */
看起来不错。