TS3.5 introduced a change to enforce more type safety when writing to properties whose key is a union. In terms of just the types, the compiler can't tell the difference between what you're trying to do, and the definitely unsafe code here:
function badCopy(k1: keyof ITest, k2: keyof ITest, o: ITest) {
o[k2] = o[k1]; // error!
}
Here, the key k1 and k2 are exactly the same type: keyof ITest. But there's a good chance you're trying to blindly copy a property from one key to an incompatible property at another key. Because the key values in k1 and k2 might not be the same, despite being the same type. That's unsafe, so you get an error.
Unfortunately that change also causes what you're doing to get deemed as "possibly unsafe" even though you know for sure that e is the same exact value in both the read and the write. This is currently considered a design limitation in TypeScript, although it's possible that they might consider special-casing identical key identifiers. If you care about that, you might want to go to the related GitHub issue (it looks like microsoft/TypeScript#32693 is still listed as "in discussion") and give it a or describe your use case if it's more compelling than what's listed there.
That being said there are workarounds until and unless that gets resolved:
The compiler still allows the loophole where an identical type is assignable to itself, as long as the compiler can't see that you are using a union-type as your key type. Often you can make your functions more generic, like this:
function copy<K extends keyof ITest>(e: K, source: ITest, dest: ITest) {
dest[e] = source[e]; // no error now
}
Or, if you don't want to do that, just accept that you know better than the compiler here and use a type assertion to tell it not to worry:
function copyAssert(e: keyof ITest, source: ITest, dest: ITest) {
dest[e] = source[e] as any; // one way
dest[e] = source[e] as ITest["first"] & ITest["second"]; // more explicit
}
Hopefully one of those works for you. Good luck!
Link to code