Home > Software design >  How to infer the value type of an object given one of its keys?
How to infer the value type of an object given one of its keys?

Time:09-16

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

Playground link to code

  • Related