Это работает как задумано. Представьте, что вы вызываете 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