您的第一个假设是错误的:
const foo = ['a', 'b'] as const; // Type is ['a', 'b'], a tuple of literals
const bar = ['a', 'b']; // Type is ('a' | 'b')[], a list of a union of literals
使用['a', 'b']
不管const
你可以这样输入:
type ObjectFromList<T extends ReadonlyArray<string>, V = string> = {
[K in (T extends ReadonlyArray<infer U> ? U : never)]: V
};
操场上的完整示例
解释:
-
T extends ReadonlyArray<string>
需要一个类型参数,该参数是一个数组,其中的元素可以变成字符串,只读允许您使用const
。每个字符串文字类型都可以传递到字符串中。
-
T extends ReadonlyArray<infer U> ? U : never
是一个条件条件,意思是:“如果 T 是一个数组,则获取其元素的类型(U
),否则没有类型”。
我们需要 T 来扩展一个数组,所以我们可以设置 never after:
这意味着我们知道它永远不会发生。infer U
将推断 T 可能的最小类型集,在您的情况下是字符串文字的并集 ('a' | 'b'
)
-
[K in ...]: V
使用数组元素中所有可能的值作为指向 type 值的键V
(我们将默认值设置为string
,但您可以通过另一个)。
最后,关于减少。您需要设置迭代期间正在使用的类型:
const result: Type = arrayData.reduce((r, key) => {
return {
...r,
[key]: false,
}
}, {} as Type); // Here
要精确限制类型,您需要通过输入初始累加器来输入reduce,并输入函数的返回值:
const result: Type = arrayData.reduce((r, key): Type /* HERE */ => {
return {
...r,
[key]: false,
}
}, {} as Type);
操场上的完整示例