ais
ais

Reputation: 2624

Why can't I write to object property with index type inference

I have this function

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] has type number but I cannot write number to it

Type '123' is not assignable to type 'T[K]'.

How to fix it?

Upvotes: 3

Views: 74

Answers (1)

bela53
bela53

Reputation: 3485

This is working as intended. Imagine you invoke foo like this:

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

Then T[K] won't be number, but 42 (a subtype) - an assignment of 123 to a wouldn't be valid anymore. Inside foo body, we only know for sure, that T[K] is some kind of number (generic constraint of T), but not what the exact type is.

Hence TS will emit the error Type '123' is not assignable to type 'T[K]' - the compiler cannot ensure, that 123 is the right type, as generic types are set by the caller of foo. The only type that can be checked statically is T[K].

To write number to certain properties K, you can change the signature as follows:

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

Upvotes: 4

Related Questions