According to some business rules, I created an aggregation function that I need to type correctly.
The function (JS):
It takes:
- Initial object.
nobjects.
export function aggregateObjects(initialObject, ...newObjects) {
const aggregate = (objectA, objectB) => {
return Object.keys(objectB).reduce(
(acc, key) => ({
...acc,
[key]: [...(acc[key] ?? []), ...(objectB[key] ?? [])],
}),
objectA
);
};
return newObjects.reduce(
(aggregatedObjects, newObject) => aggregate(aggregatedObjects, newObject),
initialObject
);
}
How to use it (TypeScript):
Here is an example of two new objects passed to aggregateObjects, but it should work with 5, 10, ...
const initialObject = {
a: [objectOfType1],
};
const newObject1 = {
a: [objectOfType2],
b: [objectOfType1],
};
const newObject2 = {
c: [objectOfType1, objectOfType2],
};
const result = aggregateObjects(initialObject, [newObject1, newObject2]);
What we expect (TypeScript):
According to previous example, we expect this result:
ashould be typed as an array ofObjectType1orObjectType2.bshould be typed as an array ofObjectType1.cshould be typed as an array ofObjectType1orObjectType2.
type Result = {
a: (ObjectType1 | ObjectType2)[];
b: ObjectType1[];
c: (ObjectType1 | ObjectType2)[];
};
What I tried (TypeScript):
Of course, it does not work:
- Internal
aggregateseems OK (even if there's some issues related to spread). - Outside, I didn't find a solution to correctly type return value.
Note that CombineObjs is a TS helper inspired from https://dev.to/svehla/typescript-how-to-deep-merge-170c
export function aggregateObjects<T extends object, U extends any[]>(
initialObjects: T,
...newObjects: U
) {
const aggregate = <A extends object, B extends object>(
objectA: A,
objectB: B
): CombineObjs<A, B> => {
return (Object.keys(objectB) as Array<keyof B>).reduce(
(acc, key) => ({
...acc,
[key]: [
// @ts-ignore
...(acc[key as keyof CombineObjs<A, B>] ?? []),
// @ts-ignore
...(objectB[key] ?? []),
],
}),
objectA as unknown as CombineObjs<A, B>
);
};
return newObjects.reduce(
(aggregatedObjects, newObject) => aggregate(aggregatedObjects, newObject),
initialObjects
);
}
Thanks for your solutions.
cbe of typeObjectType2[]and not(ObjectType1 | ObjectType2)[]? It would be helpful if at least the JavaScript part was working before trying to help you with the typing.CombineObjsTS util taking only two generics, and I need to have it working onngenerics. I didn't find a solution. Finally, the return type I want is a combine of multiple objects (but I can't use this type).ObjectTypes? Are they always supposed to be a flat object structure where the values are tuples? Or can they have an arbitrary shape? What would happen ifa: "123"?