首页 > 解决方案 > 如何在 TypeScript 中将数组转换为对象?

问题描述

我正在尝试输入下面的实用函数,它接受一个数组并返回一个对象,如下所示

const convertListToMap = (list, key, secondKey) => {
  const map = {};
  
  for (const ele of list) {
    map[ele[key]] = ele[secondKey]
  }
  
  return map;
}


console.log(convertListToMap([{name: 'isaac', age: 17}, {name: 'john', age: 20}], 'name', 'age'));

console.log(convertListToMap([{race: 'chinese', language: 'mandarin'}, {race: 'malay', language: 'melayu'}], 'race', 'language'));

正如你所知道的keysecondKey它是动态的,取决于参数list,所以我想generics这是要走的路。下面是我的尝试

const convertListToMap = <
  T extends object,
  U extends keyof T,
  V extends keyof T
>(
  list: T[],
  key: U,
  secondKey: V
) => {
  const map = {} as Record<U, V>;
  for (const ele of list) {
    map[ele[key]] = ele[secondKey];
  }
  return map;
};

但是,上面给了我错误Type 'T[U]' cannot be used to index type 'Record<U, V>',想知道我做错了哪一部分?

更新

我最近的尝试是更新map如下的签名

  const map = {} as Record<T[U], T[V]>;
  for (const ele of list) {
    map[ele[key]] = ele[secondKey];
  }
  return map;

通过最新的尝试,对map变量的值赋值很好,但我在记录声明行遇到错误,错误如下

类型 'T[U]' 不满足约束 'string | 号码 | 象征'。类型 'T[keyof T]' 不可分配给类型 'string | 号码 | 象征'。键入'T[字符串] | T[号码] | T[symbol]' 不能分配给类型 'string | 号码 | 象征'。类型 'T[string]' 不能分配给类型 'string | 号码 | 象征'。类型 'T[string]' 不能分配给类型 'symbol'。类型 'T[keyof T]' 不能分配给类型 'symbol'。类型 'T[U]' 不能分配给类型 'symbol'。类型 'T[keyof T]' 不能分配给类型 'symbol'。键入'T[字符串] | T[号码] | T[symbol]' 不能分配给类型 'symbol'。类型 'T[string]' 不可分配给类型 'symbol'.ts(2344)

标签: javascripttypescriptgenerics

解决方案


最后一次尝试的问题是,它Record似乎只期望string | number | symbol,并且由于 TypeScript 不确定T[U]会发生什么,因此它抛出了错误。我发现我们可以告诉 TS 更多信息T如下

const convertListToMap = <
  T extends { [key: string|number]: string | number },
  U extends keyof T,
  V extends keyof T
>(
  list: T[],
  key: U,
  secondKey: V
) => {
  const map = {} as Record<T[U], T[V]>;
  for (const ele of list) {
    map[ele[key]] = ele[secondKey];
  }
  return map;
};

从上面,我们告诉 typescript 这T将是一个带有keyof的对象string,并且值将是 type string | number,这样,TypeScript 对定义感到满意Record<T[U], T[V]>

此解决方案效果很好,TS 可以正确推断

const personObj = convertListToMap([{name: 'isaac', age: 17}, {name: 'john', age: 20}], 'name', 'age')
// const personObj: Record<string, number>

const languageObj = convertListToMap([{race: 'chinese', language: 'mandarin'}, {race: 'malay', language: 'melayu'}], 'race', 'language')
// const languageObj: Record<string,string>

推荐阅读