由于标题不太清楚,我将尝试详细说明。
因此,我有一些不同类型的对象,其中所有对象唯一相同的是一个属性,其名称(而非类型)在所有对象中都相同。它们都是主要对象的属性。
我将运行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);
我希望这更加清楚,我知道这是一个非常好的用例。
预先感谢您的帮助。
答案 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 T
到Record<keyof T, {propertyWithSameName: unknown}>
之类的类型,类似于您的WhatIKnowAboutTheObject
:Record<K, V>
是具有键{{1 }}和值K
。因此,约束条件表明“ V
是其属性必须扩展T
的类型,或者“ {propertyWithSameName: unknown}
的属性本身必须具有T
的属性”。
我不确定我是否真的喜欢放在propertyWithSameName
内的怪异reduce()
函数,因此可以根据需要随时进行更改,但希望您能了解打字的外观。
好的,希望能有所帮助。祝你好运!