根据Typescript中多个对象的同名属性创建对象类型?

时间:2018-12-29 02:10:52

标签: typescript typescript-typings

由于标题不太清楚,我将尝试详细说明。

因此,我有一些不同类型的对象,其中所有对象唯一相同的是一个属性,其名称(而非类型)在所有对象中都相同。它们都是主要对象的属性。

我将运行reduce来创建具有属性的新对象,其中值是那些对象中具有相同名称的那些属性的值,而属性名称是来自主对象的属性名称。

我需要的是,这种reduce的结果类型是带有这些道具的对象。但我也需要将此类型设置为可重用。

所以说我有以下对象结构:

type SameFoo = {
  a: string;
};

type SameBar = {
  b: number;
};

type FooType = {
  propertyWithSameName: SameFoo;
};

type BarType = {
  propertyWithSameName: SameBar;
};

type Main = {
  foo: FooType;
  bar: BarType;
};

const main: Main = {
  foo: { propertyWithSameName: { a: 'something' } },
  bar: { propertyWithSameName: { b: 1 } }
};

现在,我将运行一个reduce将其转换为:

const result = {
  foo: { a: 'something' },
  bar: { b: 1 }
};

这里的问题是我不知道输入类型是属性或属性的名称,我在这里唯一了解的是具有相同名称的属性的结构和名称。

// What I know about the structure:
type WhatIKnowAboutTheObject = {
  [propName: string]: {
    propertyWithSameName: unknown;
    [key: string]: unknown;
  }
}

但是由于我希望对此进行强类型化,因此我需要使reduce输出对象具有正确的类型,或者可能具有对其进行转换的类型,例如:

type Result = TransformType<Main>;

// Resulting type:
// type Result = {
//   foo: SameFoo;
//   bar: SameBar;
// };

所以我可以做类似的事情:

type Result = TransformType<Main>;
const result: Result = Object.keys(main).reduce(..., {} as Result);

我希望这更加清楚,我知道这是一个非常好的用例。

预先感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

所以,我认为,您正在寻找这样的东西:

function transform<T extends Record<keyof T, { propertyWithSameName: unknown }>>(
  obj: T
) {
  return (Object.keys(obj) as Array<keyof T>).reduce(
      (acc, k) => (acc[k] = obj[k].propertyWithSameName, acc),
      {} as {
        [K in keyof T]: T[K]['propertyWithSameName'];
      });
}

const result = transform(main);
// const result: {
//   foo: SameFoo;
//   bar: SameBar;
// }

基本上,您想要的TransformType<>是一个mapped type,它会遍历所有属性并为每个属性执行propertyWithSameName中的lookup。具体来说,如果对象的类型为T,则需要{[K in keyof T]: T[K]['propertyWithSameName'];})。请注意,您需要constrain TRecord<keyof T, {propertyWithSameName: unknown}>之类的类型,类似于您的WhatIKnowAboutTheObjectRecord<K, V>是具有键{{1 }}和值K。因此,约束条件表明“ V是其属性必须扩展T的类型,或者“ {propertyWithSameName: unknown}的属性本身必须具有T的属性”。

我不确定我是否真的喜欢放在propertyWithSameName内的怪异reduce()函数,因此可以根据需要随时进行更改,但希望您能了解打字的外观。

好的,希望能有所帮助。祝你好运!