Reputation: 33
I have the following code:
interface MyType {
a: string;
b: number;
}
class SomeClass {
// ... more things going on
beta: MyType = {a: 'Lorem', b: 3};
myFunction(alpha: MyType) {
// beta is an object of type MyType
for (const key in alpha) {
this.beta[key as keyof typeof this.beta] = alpha[key as keyof typeof alpha] ?? '';
}
}
}
see identical playground here.
However, this produces the error:
Element implicitly has an 'any' type because expression of type 'string | number | symbol' can't be used to index type 'MyType'.
No index signature with a parameter of type 'string' was found on type 'MyType'.
I've tried playing around with it for a long time, tweaking it, and it still doesn't work -- I've no idea why. (I'm using keyof typeof this.beta
for simplicity but keyof MyType
doesn't work either).
Thanks for the help in advance.
Upvotes: 1
Views: 151
Reputation: 33061
I believe that this question is very similar to yours.
Consider this example:
interface MyType {
a: string;
b: number;
}
class SomeClass {
beta: MyType = { a: 'Lorem', b: 3 };
myFunction(alpha: MyType) {
// beta is an object of type MyType
for (const key in alpha) {
const x = this.beta[key as keyof MyType] // string | number
const y = alpha[key as keyof typeof alpha] // number | number
this.beta[key as keyof MyType] = alpha[key as keyof typeof alpha] ?? ''; // expected error
}
}
}
As you see, x
and y
can be a string
or number
.
declare var x: string | number;
x = 42;
x = 'str'
Since TS is about static type checking, it is unable to figure out whether this.beta[key]
has same type as alpha[keys]
, they both are string | number
.
You are getting Type 'string | number' is not assignable to type 'never'
This is because objects are contravariant in their key types. And candidates for the same type variable in contra-variant positions causes an intersection type to be inferred. Hence string & number
gives never
.
My advise - don't mutate values in typescript.
You can find more explanations and examples in my blog
How to fix it?
interface MyType {
a: string;
b: number;
}
class SomeClass {
beta: MyType = { a: 'Lorem', b: 3 };
myFunction(alpha: MyType) {
const result = (Object.keys(alpha) as Array<keyof MyType>).reduce<MyType>((acc, elem) => ({
...acc,
[elem]: alpha[elem]
}), this.beta)
this.beta = result
}
}
Upvotes: 1