Typescript remember instance order in object literal?

I am using the latest version of Typescript: 2.6.2 .

I encounter a strange situation where, if I do foo({a:1,b:2}) , everything does not work, and if I do: foo({b:2,a:1}) , they work.

I have a generic class, an interface that has 2 properties and a function.

Here is the code:

 class MyClass<T> { value: T; next(value: T): void { } } export enum StateKey { backlogItems='backlogItems'} export interface State { backlogItems : number[]; [key: string]: any } class A { private subj = new MyClass<State>(); public set<T>(name: StateKey, state: T) { this.subj.next({ backlogItems: [...this.subj.value.backlogItems] , [name]:state //<--- error here }) } } 

I get an error message:

  Argument of type '{ [name]: T; }' is not assignable to parameter of type 'State'. Types of property 'backlogItems' are incompatible. Type 'T' is not assignable to type 'number[]'. 

But if I change the order of the literals in the object:

from:

 this.subj.next({ backlogItems: [...this.subj.value.backlogItems], [name]: state }) 

to:

  this.subj.next({ [name]:state, backlogItems: [...this.subj.value.backlogItems] }) 
  • Then there is no mistake

Question

Why does reordering make it compile?

Image ID

Typescript Playground Demo

+7
javascript typescript
source share
1 answer

It compiles without errors if you change the line in the StateKey enum to another value, for example

 export enum StateKey { backlogItems='somethingElse'} 

(the error also disappears if you add more values ​​to the enumeration)

The compiler draws type inference and discovers that [name] in your next() function argument can only be backlogItems , which is declared as number[] .

Thus, both variants of the object literal assign two different values ​​to the same property, so the order of assignments - the latter wins, basically. The compiler reports an error if the last value assigned is incompatible with the declared property type - T incompatible with number[] .

UPDATE

In addition, to save the code and simply get rid of the error, you can make the compiler forget about the type that it made for name by assigning it to an intermediate variable with the type string :

 class MyClass<T> { value: T; next(value: T): void { } } export enum StateKey { backlogItems='backlogItems'} export interface State { backlogItems : number[]; [key: string]: any } class A { private subj = new MyClass<State>(); public set<T>(name: StateKey, state: T) { const key: string = name; this.subj.next({ backlogItems: [...this.subj.value.backlogItems] , [key]:state }) } } 
+2
source share

All Articles