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