The root cause of the ts error is that:
Object.keys(payload) returns a string[] type, rather than (keyof T)[].
Typescript does that intentionally, because you can do something like this without any error:
interface Person {
name:string,
age:number
}
const person = {
name:'bob',
age:12,
randomKey: 123, // <-- you can set any extra keys
}
function takePerson(person: Person) {
return Object.keys(person);
}
takePerson(person); // <-- returns ["name", "age", "randomKey"]!
More context around can be found: https://stackoverflow.com/a/55012175/9634568
I don't recommend to add the any index signature as other answers have suggested, unless you could set arbitrary keys at runtime. Because it will make your type check work unexpectedly, if you don't understand how it works. For example, a playground shows how getter and setter use cases cannot catch typos:
interface Person {
name:string,
age:number,
[key: string]: any
}
const bob:Person = {
name:'bob',
age:12,
agee: "typo" // <- no ts error any more
}
bob.agee // <- no ts error any more
In your example, you can just simply do this as shown in this playground:
function setSome<T extends Person>(payload:Partial<T>){
Object.assign(bob, payload);
}
// Or this, if you need to do more things before setting values
function setSome2<T extends Person>(payload:Partial<T>){
for (let key in payload) {
// do something here, e.g., filter key
Object.assign(bob, { [key]: payload[key] });
}
}