In my code, there is a method designed to extend an existing key-value map with objects of the same type. This can be useful when working with database query results.
export function extendWith<
T extends { id: string | number },
O =
| (T["id"] extends string | number ? Record<T["id"], T> : never)
| (T["id"] extends string | number ? Partial<Record<T["id"], T>> : never)
>(obj: O, vals: T | T[]): O {
const extended = { ...obj };
const values = Array.isArray(vals) ? vals : [vals];
for (const val of values) {
if (val !== undefined) {
const prop = val["id"];
if (
typeof prop === "string" ||
typeof prop === "number" ||
typeof prop === "symbol"
) {
(extended as any)[prop] =
prop in obj ? { ...(obj as any)[prop], ...val } : val;
}
}
}
return extended;
}
When I use this method and specify the type explicitly as shown below, TypeScript correctly detects errors related to incorrect object properties.
interface Photo {
id: number;
name: string;
}
const photos: { [key: number]: Photo } = {
1: { id: 1, name: "photo-1" },
2: { id: 2, name: "photo-2" }
};
const extendedPhotos = extendWith<Photo>(photos, { id: 4, name: 3 });
However, when I omit the explicit type declaration in the extendWith
call, TypeScript no longer shows these errors. This behavior seems to be related to TypeScript's generic inference system.
If you have any insights on how to ensure correct type inference in this scenario, please share your tips! Your guidance would be greatly appreciated.
Feel free to experiment with a sandbox version of the code here.