Adavo
Adavo

Reputation: 925

Typescript lambdas and closure (scope)

I load some data for multiple users and I want to store it into a javascript array. In pure typescript, I will write it like that:

for(var i = 0; i < 5; i++) {
   promise[i] = httpquery.then( 
     (data) => { this.usersData[i] = data }
   );
)

...

this.$q.all[promise].then(......

unfortunately, my typescript lambda protect only this (and not the variable i). So in my case it will always store the data in this.usersData[5].

Right, I need a closure, and what lambda expression do is a bit similar to a closure as far as I understand this typescript's part of language.

so let try to do something with Typescript :

for(var i = 0; i < 5; i++) {
   promise[i] = (index = i) => {
       return httpquery.then( 
          (data) => { this.usersData[index] = data }
       );
   }();
)

which not work at all (not even compile). Why ? because seems that () => {} is not really a function. I solved this by using this way :

for(var i = 0; i < 5; i++) {
   var getData = (index = i) => {
       return httpquery.then( 
          (data) => { this.usersData[index] = data }
       );
   };
   promise[i] = getData();
)

which I found not super beautiful :-p. So my question is: how to proceed in this case of issue ? Like I did ? Or there is a way to use the lambda in typescript in a more beautiful way ? And why

 () => {}() 

isn't working but

 var test = () => {}; 
 test(); 

works ? It it because of the typescript compiler which is not "smart" enough to understand that the lambda is a function ?

Thanks.

Upvotes: 4

Views: 2355

Answers (1)

Sean Vieira
Sean Vieira

Reputation: 159905

The reason why:

promise[i] = (index = i) => {
  return httpquery.then( 
    (data) => { this.usersData[index] = data }
  );
}();

doesn't parse is because it isn't valid JavaScript (var x = a => { return a + 1; }(3) is a SyntaxError in JavaScript as well as TypeScript. Simply wrapping the lambda in parenthesis is enough to make it a valid expression.

However, simply doing that will not fix your capturing issue - default arguments are evaluated on each call, and so they will all point at the final bound value of the var.

Instead you can either:

A) Switch to using let in your initializer (in which case TypeScript will automatically do the right thing:

for(let i = 0; i < 5; i++) {
  promise[i] = httpquery.then(data => this.usersData[i] = data);
}

B) Manually create the closure yourself:

for(var i = 0; i < 5; i++) {
  promise[i] = (index => httpquery.then(data => this.usersData[index] = data))(i);
}

Upvotes: 3

Related Questions