Почему я не могу написать свойство объекта с выводом типа индекса - PullRequest
3 голосов
/ 24 марта 2020

У меня есть эта функция

function foo<T extends { [P in K]: number }, K extends keyof T>(obj: T, key: K): void {
  const x: number = obj[key]
  obj[key] = 123 //error
}

obj[key] имеет тип number, но я не могу записать в него номер

Тип "123" не может быть назначен типу " T [K] '.

Как это исправить?

1 Ответ

4 голосов
/ 24 марта 2020

Это работает как задумано. Представьте, что вы вызываете foo следующим образом:

const obj = {a: 42} as const
foo(obj,"a") 
// foo<{readonly a: 42; }, "a">(obj: { readonly a: 42; }, key: "a"): void

Тогда T[K] не будет number, но 42 (подтип) - назначение от 123 до a больше не будет действительным. Внутри тела foo мы точно знаем, что T[K] - это какой-то number (общее c ограничение T), но не то, что точный тип.

Следовательно, TS выдаст ошибку Type '123' is not assignable to type 'T[K]' - компилятор не может гарантировать, что 123 является правильным типом, так как типы generi c устанавливаются вызывающей стороной из foo , Единственный тип, который может быть проверен статически, это T[K].

Чтобы записать number для определенных свойств K, вы можете изменить подпись следующим образом:

function foo<K extends PropertyKey>(obj: Record<K, number>, key: K): void {
  const x: number = obj[key]
  obj[key] = 123 
}

const obj = { foo: 1, bar: true }
foo(obj, 'foo') // works

TS Playground sample

...