最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to convert array to object in TypeScript? - Stack Overflow

programmeradmin3浏览0评论

I am trying to typed the below utility function which takes in an array and return an object as below

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'));

I am trying to typed the below utility function which takes in an array and return an object as below

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'));

As you can tell key and secondKey is sort of dynamic, depending on the parameter list, so I guess generics is the way to go. Below is my attempt

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;
};

However, the above giving me error Type 'T[U]' cannot be used to index type 'Record<U, V>', wondering which part I've done wrong?

UPDATES

My latest attempt is to update the signature of map as below

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

With this latest attempt, value assignment to map variable is fine, but I'm getting error at Record declaration line with below error

Type 'T[U]' does not satisfy the constraint 'string | number | symbol'. Type 'T[keyof T]' is not assignable to type 'string | number | symbol'. Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'string | number | symbol'. Type 'T[string]' is not assignable to type 'string | number | symbol'. Type 'T[string]' is not assignable to type 'symbol'. Type 'T[keyof T]' is not assignable to type 'symbol'. Type 'T[U]' is not assignable to type 'symbol'. Type 'T[keyof T]' is not assignable to type 'symbol'. Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'symbol'. Type 'T[string]' is not assignable to type 'symbol'.ts(2344)

Share Improve this question edited Sep 28, 2021 at 12:53 Isaac asked Sep 28, 2021 at 7:37 IsaacIsaac 12.9k18 gold badges64 silver badges134 bronze badges 3
  • Ignore me (deleted the ment). I think the main problem is that your map is not type Record<U, V> since you're putting in the values from T, not the keys – Phil Commented Sep 28, 2021 at 7:49
  • @Phil: Good point, I even tried const map = {} as Record<T[U], T[V]>; but it doesn't work either haha – Isaac Commented Sep 28, 2021 at 7:50
  • @Phil: I've finally found a solution, maybe can take a look if you're interested :D – Isaac Commented Sep 28, 2021 at 8:22
Add a ment  | 

1 Answer 1

Reset to default 4

The problem with the last attempt was that Record seemed to expect only string | number | symbol, and since TypeScript unsure what T[U] gonna be, hence it threw the error. I found that we can tell TS a little bit more about T as below

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;
};

From the above, we are telling typescript that T is gonna be an object with key of string, and the value is gonna be of type string | number, with that, TypeScript is happy with the definition Record<T[U], T[V]>

This solution works great and TS can infer correctly

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>
发布评论

评论列表(0)

  1. 暂无评论