In many of my react forms I want to use a generic form change handler that can handle updating the different fields of a state object.
How do I correctly type this change handler so that the below invocations are resulting in a compile error:
interface Data {
a: string;
b: number;
}
let data: Data = {a: "a", b: 1};
function changeHandler<T>(field: keyof Data, value: T) {
data = {...data, [field]: value}
}
// should compile
changeHandler("a", "aa");
changeHandler("b", 11);
// should not compile
changeHandler("a", 1);
changeHandler("b", "b");
console.log(data);
The example is simplified and in the real application React.useState
is used instead of using a let
variable.
Instead of adding a generic parameter for the value, add it for the key, and by using indexed access types get the correct type for the value:
function changeHandler<T extends keyof Data>(field: T, value: Data[T]) {
data = {...data, [field]: value}
}
Testing:
changeHandler("a", "aa"); // no error
changeHandler("b", 11); // no error
changeHandler("a", 1); // error
changeHandler("b", "b"); // error