Is there an alias for 'this' in TypeScript?
As covered by some of the other answers, using the arrow syntax to define a function causes references to this
to always refer to the enclosing class.
So to answer your question, here are two simple workarounds.
Reference the method using the arrow syntax
constructor(public id: string) {
this.textarea = $(id);
this.textarea.focusin(e => this.onFocusIn(e));
}
Define the method using the arrow syntax
onFocusIn = (e: JQueryEventObject) => {
var height = this.textarea.css('height');
}
The scope of this
is preserved when using the arrow function syntax () => { ... }
- here is an example taken from TypeScript For JavaScript Programmers.
var ScopeExample = {
text: "Text from outer function",
run: function() {
setTimeout( () => {
alert(this.text);
}, 1000);
}
};
Note that this.text
gives you Text from outer function
because the arrow function syntax preserves the "lexical scope".
So as stated there is no TypeScript mechanism for ensuring a method is always bound to its this
pointer (and this isn't just a jQuery issue.) That doesn't mean there isn't a reasonably straightforward way to address this issue. What you need is to generate a proxy for your method that restores the this
pointer before calling your callback. You then need to wrap your callback with that proxy before passing it into the event. jQuery has a built in mechanism for this called jQuery.proxy()
. Here's an example of your above code using that method (notice the added $.proxy()
call.)
class Editor {
textarea: JQuery;
constructor(public id: string) {
this.textarea = $(id);
this.textarea.focusin($.proxy(onFocusIn, this));
}
onFocusIn(e: JQueryEventObject) {
var height = this.textarea.css('height'); // <-- This is not good.
}
}
That's a reasonable solution but I've personally found that developers often forget to include the proxy call so I've come up with an alternate TypeScript based solution to this problem. Using, the HasCallbacks
class below all you need do is derive your class from HasCallbacks
and then any methods prefixed with 'cb_'
will have their this
pointer permanently bound. You simply can't call that method with a different this
pointer which in most cases is preferable. Either mechanism works so its just whichever you find easier to use.
class HasCallbacks {
constructor() {
var _this = this, _constructor = (<any>this).constructor;
if (!_constructor.__cb__) {
_constructor.__cb__ = {};
for (var m in this) {
var fn = this[m];
if (typeof fn === 'function' && m.indexOf('cb_') == 0) {
_constructor.__cb__[m] = fn;
}
}
}
for (var m in _constructor.__cb__) {
(function (m, fn) {
_this[m] = function () {
return fn.apply(_this, Array.prototype.slice.call(arguments));
};
})(m, _constructor.__cb__[m]);
}
}
}
class Foo extends HasCallbacks {
private label = 'test';
constructor() {
super();
}
public cb_Bar() {
alert(this.label);
}
}
var x = new Foo();
x.cb_Bar.call({});