3

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.

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

1 Comment

I have a question about this, why cannot infer the type of value. the follow code always result failure. ts function updateProp<TObj, K extends keyof TObj>(obj: TObj, key: K, value: TObj[K]) { obj[key] = value; switch(key){ case 'myDate': let s: string = value; console.log(s); break; default: break; } }
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.