Cities Cities - 26 days ago 8
Javascript Question

TypeScript, Angular 1.x: How do lambda functions affect property resolution?

EDIT:

I was able to fix the issue, but I am not sure why. So, I modified this question to reflect where I stand now. I'm leaving the old question for reference.

NEW QUESTION:

Changing a lambda function to an old-style function fixed an issue where the TS compiler was unable to find a property on

$state
. I have no idea why this is the case. So, my question now is...

How do lambda functions affect property resolution? and..

How do can I determine when to use a lambda vs. an old-style function?

Fixed property resolution by reverting to old-style function:

enter image description here

OLD QUESTION BELOW:

Title: TypeScript, Angular 1.x: $state.go does not exist -- but it does elsewhere in the same file

I'm converting an Angular 1.5 app from vanilla JS to TypeScript. I'm running into a strange issue where the method
go
both on
$state
exists and does not exist within the same class.

(It may be hard to see in the image below, but notice that in the second
this.$state.go
,
go
has a red underline because the compiler thinks the property does not exist)

enter image description here

Here is the full class:

export class LogoutAndInfoController implements ILogoutAndInfo {
public memberInfo: Object;
static $inject = [
'$http', '$state', 'AuthService', 'API_ENDPOINT', 'UserInfoService'
];

constructor(private $http: angular.IHttpService, private $state: angular.ui.IStateProvider,
private AuthService: AuthService, private API_ENDPOINT: IAPI_ENDPOINT, private UserInfoService: UserInfoService) {
this.memberInfo = {};
}

destroySession(): void {
this.AuthService.logout();
}

getInfo(): void {
this.$http.get(this.API_ENDPOINT["url"] + '/memberinfo').then(function (result) {
this.memberInfo = result.data["user"];
this.$state.go('login');
});
}

logout(): void {
this.AuthService.logout().then((result: any) => {
this.UserInfoService.resetUser();
this.$state.go('login');
});
}
}


I am very new to both TS and TS within the Angular framework. So, please let me know if there is any other code that needs to be seen before we can debug.

Answer

It's actually due to this acting...weirdly in Javascript compared to most other languages you may have used.

In your first example, you call $http.get(). Because of how this works in JS, the get() function will be called, with this being set to whatever this.$http is in this case. This is where the funky-ness starts though. this is only set when you call a method on an object, and remains the same when a new function is called. This means that when $http.get() calls your callback, this is still set to $http and thus $state doesn't exist.

This is why you see the pattern of var self = this; all over the place. It allows you to have a binding to this that you know about, so the following would work:

var self = this;
this.$http.get(..., function() {
    self.$state.go()
});

Lambda functions, on the other hand, bind differently. So called "arrow functions" don't have their own this context, and thus close over the this in the function in which they were created, so they work as you expect.

Further sources:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_binding_of_this