I'm guessing that you're running into the issue where Object.keys(obj) returns string[] instead of something like (keyof typeof obj)[]. It's a common issue that gets reported a lot. The reason Object.keys() has to return string[] is because types in TypeScript are open in the sense that an object has to have at least the properties described by a type for it to match. So the only type-safe return value is string[]. See this comment for more information.
This means that assuming data.details is of type Idetails (I don't see that in your code... data is just of type any; you should tighten that up), all you know is that it has at least the primary and secondary properties, but it might have more. For example, data.details might be
const details = {
primary: { beginningBalance: "$0", endingBalance: "$200" },
secondary: { beginningBalance: "25¢", endingBalance: "10¢" },
tertiary: { beginningBalance: "₿100,000", endingBalance: "₿0.001" }
}
And therefore key is not a valid index into response.details, since key might be "teritary".
The easiest way to deal with this is just to assert that Object.keys(data.details) returns just the keys you know about. Sure, it's possible that at runtime there will be extra keys, and the code will just copy those extra properties into response.details... which is probably harmless since it doesn't stop response.details from being a valid Idetails. Here's how you could do it:
(Object.keys(data.details) as (keyof Idetails)[]).forEach((key) => {
response.details[key] = data.details[key]; // okay
});
Notice that we are using the as keyword to assert that Object.keys(data.details) returns a (keyof Idetails)[]. Now, key is inferred to be "primary" | "secondary", and the compiler is happy with the assignment.
There are other ways to deal with the issue in the case where you want to prevent copying extra properties, such as manually specifying the array of keys to copy without inspecting data.details at all:
// helper function to narrow array to string literals
const stringLiterals = <T extends string[]>(...args: T) => args;
// stringLiterals("primary", "secondary") is inferred as type ["primary", "secondary"]
stringLiterals("primary", "secondary").forEach((key) => {
response.details[key] = data.details[key]; // okay
});
This is now completely type safe and doesn't require any type assertions, but it might be more trouble than it's worth.
Hope that helps; good luck!