当我在Typescript中有一个显式扩展Object的类时,则尝试调用该类的对象方法会失败:
class Example extends Object {
constructor() {
super();
}
public getHello() : string {
return "Hello";
}
}
let greeter = new Example();
alert(greeter.getHello());
错误:greeter.getHello is not a function
。这是为什么?如果我删除了extends
子句和super()
的调用,那么它将突然起作用。
我的问题是代码是从自定义的JSweet版本自动生成的,而我们仅转换部分代码库。在类层次结构中,不应进行转译的类被简单地映射到Object
,因为extends
很难在不大量更改JSweet的情况下轻松删除。
答案 0 :(得分:7)
我认为您可以争论这是TypeScript中的错误。可能不是一个高优先级的问题,但是...:-)
这是因为Object
会忽略调用它的this
,并返回一个新的空白对象。 TypeScript编译代码的方式(针对ES5环境),最终在Object
中这样调用Example
:
function Example() {
return Object.call(this) || this;
}
Object.call(this)
的结果是一个新对象,就像您做过{}
一样。
所以解决方案是...不要这样做。 :-)
我的问题是代码是从自定义的JSweet版本自动生成的,而我们仅转换部分代码库。在类层次结构中不应该被转换的类被简单地映射到Object,因为如果不对JSweet进行大量更改就无法轻松删除扩展。
太好了。如果您可以定位到ES2015 +,则问题将消失,因为这仅与TypeScript为ES5和更早版本创建的版本有关。如果您不能这样做,恐怕听起来您想在the TypeScript issues list上提交问题,并可能提出带有修复的请求请求。 (我一直在寻找现有报告,但没有找到。)这与扩展其他内置插件(Error
,Array
)略有不同,因为有一个非常简单的解决方案:只需忽略extends
子句。
或者,正如您在评论中提到的那样,您可以拥有一个不执行任何操作的伪类,例如:
class FauxObject { }
,然后使用它代替Object
(class Example extends FauxObject
)。
为了详细起见,完整的编译版本是这样,对Object
的调用由******
标记:
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
是Object
。
答案 1 :(得分:0)
提交bug-report后,我被提示到a FAQ entry that addresses extending typescript built-ins:
在ES2015中,返回对象的构造函数将super(...)的任何调用者隐式替换为this的值。对于生成的构造函数代码,有必要捕获super(...)的任何潜在返回值并将其替换为该值。
结果,错误,数组和其他子类可能不再按预期工作。这是由于Error,Array等的构造函数使用ECMAScript 6的new.target来调整原型链的事实。但是,在ECMAScript 5中调用构造函数时,无法确保new.target的值。默认情况下,其他下层编译器通常具有相同的限制。
说明与T.J. Crowder's answer类似,此外,他们建议了其他解决方法:
建议,您可以在调用任何super(...)之后立即手动调整原型。
在我的情况下,这是将Object.setPrototypeOf(this, Example.prototype);
添加到构造函数中(或说服JSweet这样做)。
但是:
很遗憾,这些变通办法不适用于 Internet Explorer 10 及更低版本。可以将方法从原型手动复制到实例本身(即FooError.prototype到实例),但是原型链本身无法固定。
编辑:由于发现在我们的JSweet项目中更容易实现,因此我最终使用了此变通方法。