0

I would like some explanation about this error I encounter:

interface Test {
    a: number;
    b: string;
    c: string;
}
function f(obj1: Test, obj2: Test, field: keyof Test) {
    obj1[field] = obj2[field]; // Error: Type 'string | number' is not assignable to type 'never'.
}

Here are some ways I found to circumvent that error:

  • if Test contains only numbers or only strings
  • if I use obj1[field as string] = obj2[field]
  • if I change my method to function f<K extends keyof Test>(obj1: Test, obj2: Test, field: K)

But I don't understand why this code fails, is it a "bug" in typescript or am I missing something ?

Charles
  • 125
  • 1
  • 6
  • `function f(obj1: T, obj2: T, field: K) {...` Pretty sure it is a duplicate – Aleksey L. Dec 19 '21 at 14:24
  • 1
    Sorry, somehow missed the 3rd point. Anyway it can't infer they are of the same type because it sees `string | number` on both sides of assignment expression. Once generic type parameter for key is introduced - it can narrow the type according to provided value. – Aleksey L. Dec 19 '21 at 16:07

1 Answers1

1

That's because TypeScript doesn't know what type will be returned by obj2[field]. It can be either number or string. In addition, TypeScript doesn't know what type of obj1[field] will be. And because it is number | string so it decides, for type safety, that it will be never, because there are no types that is base for both number and string. Additionally, TypeScript doesn't know which property name will be in field

if Test contains only numbers or only strings

In that case, TypeScript definitely knows that all fields will be number or string, so it can infer types for both obj1[field] and obj2[field], and it will be the same type.

if I change my method to function f(obj1: Test, obj2: Test, field: K)

In that case TypeScript knows exactly type for both obj1[field] and obj2[field], so it can safely assign value.

Leemellaret
  • 197
  • 1
  • 9
  • thanks for your answer, I guess typescript isn't smart enough to detect both side of the assignment will be the same because field is the same... Still puzzled about my second point (the only one you didn't cite ^^): why casting field as string is not an error anymore, I guess it's the limitation of a type system on top of an untyped language and typescript allows to put everything in an object indexed by a string... – Charles Dec 19 '21 at 16:33
  • I did not cite second point because I was not be able to recreate this issue ^^. I guessed that you wrote index signature in `Test` and it could be `[key: string]: number | string` or even `[key: string]: any`. But this didn't help me to recreate the issue. If you say more details I will try to help – Leemellaret Dec 19 '21 at 22:03