When I have a class in Typescript that explicitely extends Object, then trying to call an object method of that class fails:
class Example extends Object {
constructor() {
super();
}
public getHello() : string {
return "Hello";
}
}
let greeter = new Example();
alert(greeter.getHello());
Error: greeter.getHello is not a function
. Why is that? If I remove the extends
-clause and the super()
call, then it suddenly works.
My problem is that the code is autogenerated from a customized JSweet version, and we only transpile some part of the codebase. Classes in the class hierarchy that should not be transpiled are simply mapped to Object
, because the extends
cannot be easily removed without changing JSweet heavily.
I think you could argue that this is a bug in TypeScript. Not a high-priority one, probably, but... :-)
It's because Object
ignores the this
it's called with, and returns a new, blank object. The way TypeScript compiles that code (when targeting ES5 environments), it ends up calling Object
like this in Example
:
function Example() {
return Object.call(this) || this;
}
The result of Object.call(this)
is a new object, as though you did {}
.
So the solution is...don't do that. :-)
My problem is that the code is autogenerated from a customized JSweet version, and we only transpile some part of the codebase. Classes in the class hierarchy that should not be transpiled are simply mapped to Object, because the extends cannot be easily removed without changing JSweet heavily.
Ouch. If you can target ES2015+, the problem goes away as this only relates to the version TypeScript creates for ES5 and earlier. If you can't, I'm afraid it sounds like you'll want to file an issue on the TypeScript issues list and perhaps do a pull request with a fix. (I went looking for an existing report and didn't find one.) This is slightly different from extending other built-ins (Error
, Array
) in that there's a very simple solution: Just ignore the extends
clause.
Or, as you mentioned in a comment, you could have a dummy class that doesn't do anything, like:
class FauxObject { }
and then use that instead of Object
(class Example extends FauxObject
).
Just for detail's sake, the full compiled version is this, the call to Object
is marked by ******
:
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Example = /** @class */ (function (_super) {
__extends(Example, _super);
function Example() {
return _super.call(this) || this; // ******
}
Example.prototype.getHello = function () {
return "Hello";
};
return Example;
}(Object));
var greeter = new Example();
alert(greeter.getHello());
_super
is Object
in your case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With