Home > Net >  Update value in object with a variable property name in Typescript
Update value in object with a variable property name in Typescript

Time:11-03

I've got this method:

updateDate(row: TaskItem, column: keyof TaskItem, date: string) {
  row[column] = date;
}

Where TaskItem looks like this:

export interface TaskItem {
  id: number,
  myDate: string
}

And I want to be able to call it like this:

updateDate(rowItem, 'myDate', '2022-02-20');

However, TS doesn't like it:

Type 'string' is not assignable to type 'never'.ts(2322)

It works as soon as I change row: TaskItem to row: any, but I'd like to be more concise.

CodePudding user response:

This can be nicely solved with generics to work safely with any object type, enforcing that the second parameter can only be a key of obj and that the third parameter is enforced to be the same type as typeof obj[key].

function updateProp<TObj, K extends keyof TObj>(obj: TObj, key: K, value: TObj[K]) {
    obj[key] = value;
}

interface TaskItem {
    id: number,
    myDate: string
}

declare const rowItem: TaskItem;

updateProp(rowItem, 'myDate', '2022-02-20');

Playground Link

CodePudding user response:

The error you are getting is completely correct, because your updateDate function assumes that the new value (date) is typeof string. However, you are not specifying which field exactly you want to update, so you have small conflict here, because even if the new value is typeof string, there is still a possibility that the column will be id (column: 'id' | 'myDate') which is not typeof string but a number.

Either you should make this function updateDate responsible only for updating the myDate field:

function updateDate(row: TaskItem, date: string) {
  row.myDate = date
}

or add a condition to make sure that you update only myDate field:

function updateDate(row: TaskItem, column: keyof TaskItem, date: string) {
  if (column === 'myDate') {
     row[column] = date
  }
}

Typescript playground

  • Related