Alex Conrad
Alex Conrad

Reputation: 359

How to infer the value type of an object given one of its keys?

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?

Upvotes: 2

Views: 57

Answers (1)

jcalz
jcalz

Reputation: 327964

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'.
);

Playground link to code

Upvotes: 2

Related Questions