Here's a toy example where I'm trying to infer the type of the value given the key provided by the user.
// Function to update an object's value by key
export const updateValueByKey = <I>(
obj: I,
keyToUpdate: keyof I,
newValue: I[keyof I] // Infers the type of all possible values, not the value of the given key
) => {
obj[keyToUpdate] = newValue;
};
// Calling the function
updateValueByKey<{ id: number; name: string; isPrivate: boolean }>(
{
id: 123,
name: "Some Note",
isPrivate: false,
},
"id", // "id" | "name" | "isPrivate"
"not a number" // number | string | boolean, should error because "id" requires a number
);
How can I ensure that the new value provided by the user matches type of the given key's value?
CodePudding user response:
If you need updateValueByKey()
to keep track of the literal type of the value passed in as keyToUpdate
, then the function needs to be generic in the type of that parameter:
export const updateValueByKey = <I, K extends keyof I>(
obj: I,
keyToUpdate: K,
newValue: I[K]
) => {
obj[keyToUpdate] = newValue;
};
And now you get the behavior you expect (assuming you don't need to manually specify I
when you call it, which you don't, since you pass a value of type I
and the compiler can infer it without a problem):
updateValueByKey(
{
id: 123,
name: "Some Note",
isPrivate: false,
},
"id",
"not a number" // error! Argument of type 'string' is
// not assignable to parameter of type 'number'.
);