如何使对象的make键在typescript中动态工作?

8ehkhllq  于 2022-12-14  发布在  TypeScript
关注(0)|答案(2)|浏览(125)

我有一个对象数据数组,我想把它们动态地转换成带有键和数组的对象。如何使对象的键在打字脚本中动态工作?
例如,如果数据如下所示:

data1 = [
  {a: 'st1', b: 1, c: 1, d: 1, e: 'e1' },
  {a: 'st2', b: 2, c: 2, d: 2, e: 'e2'},
  {a: 'st3', b: 3, c: 3, d: 3, e: 'e3'},
  {a: 'st4', b: 4, c: 4, d: 4, e: 'e4' },
]

I将其转换为:

data2= {
   a: ['st1', 'st2', 'st3', 'st4',]
   b: [1, 2, 3, 4,],
   c: [1, 2, 3, 4,],
   d: [1, 2, 3, 4,],
   e: ['e1', 'e2', 'e3', 'e4']
}

最简单的解决方案是

type Data2Props = {
  a: string[],
  b: number[],
  c: number[],
  d: number[],
  e: string[]
}

const data2: Data2Props = {
  a: [],
  b: [],
  c: [],
  d: [],
  e: []
}

data1?.forEach((item) => {
   data2.a.push(item.a)
   data2.b.push(item.b)
   data2.c.push(item.c)
   data2.d.push(item.d)
   data2.e.push(item.e)
})

但是如果键的数量增加了,有没有更好更简洁的解决方案呢?
类似的东西在javascript中可以工作,但在typescript中不行。

let keys: string[] = ['a', 'b', 'c', 'd', 'e'];

let data2 = {}
keys.forEach((key) => data2[key] = [])
data1?.forEach((item) => {
 keys.forEach((key) => data2[key].push(item[key])
}

在typescript中,它将返回键入错误。

oiopk7p5

oiopk7p51#

下面的方法需要在transpose函数中使用一组类型Assert,但是函数的使用完全是类型安全的:

const ITEM = {
    a: '',
    b: 0,
    c: 0,
    d: 0,
    e: '',
}

type Item = typeof ITEM

type TransposedItems = {
    [Key in keyof Item]: Item[Key][]
}

function transpose(items: Item[]): TransposedItems {
    const transposed: Partial<TransposedItems> = {}
    for (const key in ITEM) {
        transposed[key as keyof Item] = items.map(item => item[key as keyof Item]) as any[]
    }
    return transposed as TransposedItems
}

const data1: Item[] = [
  {a: 'st1', b: 1, c: 1, d: 1, e: 'e1' },
  {a: 'st2', b: 2, c: 2, d: 2, e: 'e2'},
  {a: 'st3', b: 3, c: 3, d: 3, e: 'e3'},
  {a: 'st4', b: 4, c: 4, d: 4, e: 'e4' },
]
console.log(transpose(data1))

诀窍是定义一个与实际元素类型相同的常量ITEM,并让类型推理来处理它。因为ITEM在运行时存在,所以我们可以迭代它的键,如果它只是一个在编译时存在的类型,那么它就是difficult to do
你也可以只使用数组中的第一个元素,但是如果对象的形状不完全相同,你会遇到麻烦。而且,只有当数组不为空时,这才有效。

sh7euo9m

sh7euo9m2#

您可以在打印脚本中执行以下操作

let data1:{[key:string]:any}[] = [
  {a: 'st1', b: 1, c: 1, d: 1, e: 'e1' },
  {a: 'st2', b: 2, c: 2, d: 2, e: 'e2'},
  {a: 'st3', b: 3, c: 3, d: 3, e: 'e3'},
  {a: 'st4', b: 4, c: 4, d: 4, e: 'e4' },
];

let keys: string[] = ['a', 'b', 'c', 'd', 'e'];

let data2:{[key:string]:any[]} = {}
keys.forEach((key) => data2[key] = [])
data1?.forEach((item) => {
 keys.forEach((key) => data2[key].push(item[key]))
});

console.log(data2);

Playground链接
或者甚至不用定义键数组

let data1:{[key:string]:string|number}[] = [
      {a: 'st1', b: 1, c: 1, d: 1, e: 'e1' },
      {a: 'st2', b: 2, c: 2, d: 2, e: 'e2'},
      {a: 'st3', b: 3, c: 3, d: 3, e: 'e3'},
      {a: 'st4', b: 4, c: 4, d: 4, e: 'e4' },
    ]  ;

  let data2:{[key:string]:any[]}={};
    data1.forEach(obj=>{
    Object.keys(obj).forEach(key=>{
    let val=obj[key];
     if(data2[key]){
     data2[key].push(val);
     }else{
     data2[key]=[val];
     }
    })
  });

  console.log(data2)

Playground链接

相关问题