You can use Object.fromEntries.
type TypeA = {
a: number;
b: number;
c: number;
};
type TypeB = {
d: number;
e: number;
c: number;
};
declare const oldObject: { [key: string]: TypeA };
const newObject: { [key: string]: TypeB } = Object.fromEntries(
Object.entries(oldObject).map(([key, value]) => [
key,
{
d: value.a,
e: value.b,
c: value.c
}
])
);
Playground Link
To elaborate a little, Object.fromEntries is, as its name suggests, the inverse of Object.entries, taking an array of [key, value] elements and creating an object where the keys are mapped to their corresponding values.
Thus, we start with Object.entries as before but, instead of using forEach to populate our new object, we map over the array, transforming each [key, value] to [key, newValue] and pass the resulting array to Object.fromEntries.
Note that, as jcalz remarks, Object.fromEntries was introduced in ES2019. If your target runtime does not support ES2019, you will need to add a polyfill such as npm:object.fromentries and correspondingly specify "lib": ["ES2019"] or higher in your tsconfig.json
I've removed the type assertion as TypeB since it is both unnecessary and would more importantly would suppress errors like forgetting or misspelling a property declared by TypeB. Type inference is one of TypeScript's most important aspects.
Your intuition around using map and reduce is a very natural one. Not only have we used map here, but reduce was frequently used to achieve the same result as Object.fromEntries before the latter was introduced.
maporreducesince they works only on arrays and not object. Converting you object to an array would be an anti-pattern and objects don't guarantee property order? according to ES5.