将字符串数组转换为打字稿中的对象键

Har*_*ual 8 typescript

我有下一个数组

const arrayData = ['a', 'b'] as const;
Run Code Online (Sandbox Code Playgroud)

该数组有下一个类型 ArrayType = ('a' | 'b')[];

我想获得与下一个类型一致的对象:

type Type = {
  a: boolean,
  b: boolean,
}
Run Code Online (Sandbox Code Playgroud)

预期对象

   const result : Type = {
     a: false,
     b: false,
   }
Run Code Online (Sandbox Code Playgroud)

我想转变arrayDataresult

const result: Type = arrayData.reduce((r, key) => {
  return {
    ...r,
    key: false,
  }
}, {});
Run Code Online (Sandbox Code Playgroud)

但这段代码没有有效的类型

Lui*_*raz 20

你的第一个假设是错误的:

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
Run Code Online (Sandbox Code Playgroud)

使用['a', 'b']不管 ,const你可以这样输入:

type ObjectFromList<T extends ReadonlyArray<string>, V = string> = {
  [K in (T extends ReadonlyArray<infer U> ? U : never)]: V
};
Run Code Online (Sandbox Code Playgroud)

操场上的完整示例

解释:

  • T extends ReadonlyArray<string>需要一个类型参数,该参数是一个数组,其中的元素可以变成字符串,只读允许您使用const. 每个字符串文字类型都可以传递到字符串中。
  • T extends ReadonlyArray<infer U> ? U : never是一个条件条件,意思是:“如果 T 是一个数组,则获取其元素的类型 ( U),否则没有类型”。
    我们需要 T 来扩展数组,因此我们可以在之后设置 never ,:这意味着我们知道它永远不会发生。 infer U将推断 T 可能的最小类型集,在您的情况下是字符串文字 ( 'a' | 'b')的并集
  • [K in ...]: V使用数组元素中的所有可能值作为指向类型值的键V(我们将默认值设置为string,但您可以传递另一个)。

最后,关于减少。您需要设置迭代期间正在使用的类型:

const result: Type = arrayData.reduce((r, key) => {
  return {
    ...r,
    [key]: false,
  }
}, {} as Type); // Here
Run Code Online (Sandbox Code Playgroud)

要精确限制类型,您需要通过输入初始累加器来输入reduce,并输入函数的返回值:

const result: Type = arrayData.reduce((r, key): Type /* HERE */ => {
  return {
    ...r,
    [key]: false,
  }
}, {} as Type);
Run Code Online (Sandbox Code Playgroud)

操场上的完整示例