Flo354 Flo354 - 4 months ago 49
Javascript Question

Weird behaviour with abstract method TypeScript

I use typescript with the reference "atmosphere.d.ts" source here. I trigged a strange behaviour with abstract methods which leads to the error :


TypeError: this.protectedMethod is not a function


Here is the typescript code :

/// <reference path="../atmosphere.d.ts" />
import Request = Atmosphere.Request;

abstract class AbstractRequest {

// The atmosphere request
protected socket: Request;

// Here we initialize the socket
protected init(url: string): void {
this.socket = {
url : "http://localhost:9000/" + url,
contentType : "application/json",
transport : "websocket" ,
fallbackTransport : "long-polling"
};

/* SOME CODE */

this.socket.onOpen = function(response) {
this.protectedMethod();
};
}

// Some protected method called in this.socket.onOpen
protected abstract protectedMethod(): void;
}

class Registration extends AbstractRequest {

// Implementation of the abstract method
protected protectedMethod(): void {
console.log("hello");
}
}


Without error, the folllowing javascript code is generated :

var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var AbstractRequest = (function () {
function AbstractRequest() {
}
// Here we initialize the socket
AbstractRequest.prototype.init = function (url) {
this.socket = {
url: "http://localhost:9000/" + url,
contentType: "application/json",
transport: "websocket",
fallbackTransport: "long-polling"
};
/* SOME CODE */
this.socket.onOpen = function (response) {
this.protectedMethod();
};
};
return AbstractRequest;
}());
var Registration = (function (_super) {
__extends(Registration, _super);
function Registration() {
_super.apply(this, arguments);
}
// Implementation of the abstract method
Registration.prototype.protectedMethod = function () {
console.log("hello");
};
return Registration;
}(AbstractRequest));
//# sourceMappingURL=test.js.map


I can't call the abstract method (may be non abstract either?) from the "socket" variable when I implement the "onOpen" method. The only workaround I found for now, is to instantiate a global variable

var registration = new Registration();


and then :

this.socket.onOpen = function(response) {
registration.protectedMethod;
};


With this workaround, I have to define "protectedMethod" public. Is there an explanation to this behaviour, and a workaround/fix? Btw, I use typescript 1.8.10

Thanks,

Answer

This is due to the way that this works in JavaScript:

var AbstractRequest = (function () {
    function AbstractRequest() { }
    AbstractRequest.prototype.init = function (url) {
        // ...snip...
        this.socket.onOpen = function (response) {
            this.protectedMethod();
        };
    };
    return AbstractRequest;
}());

When you call new AbstractRequest().socket.onOpen() this will be bound to socket not to new AbstractRequest() (this points to whatever is on the left of the dot).

You can use an arrow function to work around this. Within arrow functions this is bound to the context it was defined in, not the context it is being run in:

this.socket.onOpen = response => {
    this.protectedMethod();
};
Comments