简体   繁体   English

TypeScript数组 <T> 遗产

[英]TypeScript Array<T> inheritance

I have some experimental code that inherits from Array<T> ... 我有一些实验性代码继承自Array<T> ...

class SuperArray<T> extends Array<T> {
    constructor(...items) {
        super(...items);
    }

    public clear(): void {
        while (this.length > 0) {
            this.pop();
        }
    }
}

var array = new SuperArray("Matt", "Mark", "Luke", "John");

array.clear();

Playground 操场

I've added the clear method just to illustrate the problem. 我添加了clear方法只是为了说明问题。 When this is compiled and run in the browser, I get... 当它被编译并在浏览器中运行时,我得到...

TypeError: array.clear is not a function TypeError:array.clear不是函数

How is this completely valid code in TypeScript, but not valid in JavaScript, and is there a way to fix this? 这在TypeScript中如何完全有效,而在JavaScript中却无效,有没有办法解决此问题?

BTW this is a breaking change in TS2.1 顺便说一句,这是TS2.1中的重大变化

This TS documentation has a recommendation for a changing the prototype in your constructor TS文档提供了有关在构造函数中更改原型的建议

constructor(...items) {
    super(...items);
    Object.setPrototypeOf(this, SuperArray.prototype);
}

Your code compiles into this when targeting es5 : 定位es5时,您的代码将编译为以下代码:

var SuperArray = (function (_super) {
    __extends(SuperArray, _super);
    function SuperArray() {
        var items = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            items[_i] = arguments[_i];
        }
        return _super.apply(this, items) || this;
    }
    SuperArray.prototype.clear = function () {
        while (this.length > 0) {
            this.pop();
        }
    };
    return SuperArray;
}(Array));
var array = new SuperArray("Matt", "Mark", "Luke", "John");
array.clear();

It's not possible to extend native objects like that, which is why you're getting this error. 不可能像这样扩展本机对象,这就是为什么会出现此错误的原因。
If you'll target es6 then the compiled js will look like this: 如果您以es6为目标,那么编译后的js将如下所示:

class SuperArray extends Array {
    constructor(...items) {
        super(...items);
    }
    clear() {
        while (this.length > 0) {
            this.pop();
        }
    }
}
var array = new SuperArray("Matt", "Mark", "Luke", "John");
array.clear();

And that will work just fine (if you run it in a browser that supports es6 classes). 这样就可以正常工作(如果您在支持es6类的浏览器中运行它)。


Edit 编辑

I'll just paste parts of the article Subclassing builtins in ECMAScript 6 which explains why it can't be done with es5 : 我将仅在ECMAScript 6中粘贴文章Subclassing Builtins的部分内容,其中解释了为什么无法使用es5完成es5

Allocation obstacle: MyArray allocates the wrong kind of object 分配障碍:MyArray分配错误类型的对象
Array instances are special – the ECMAScript 6 specification calls them exotic. 数组实例很特殊– ECMAScript 6规范称它们为奇异的。 Their handling of the property length can't be replicated via normal JavaScript. 他们对属性长度的处理无法通过常规JavaScript复制。 If you invoke the constructor MyArray then an instance of MyArray is created, not an exotic object. 如果调用构造函数MyArray,则将创建MyArray的实例,而不是外部对象。

Initialization obstacle: MyArray can't use Array for initialization 初始化障碍:MyArray无法使用Array进行初始化
It is impossible to hand an existing object to Array via this – it completely ignores its this and always creates a new instance. 不可能通过this将现有对象交给Array –它完全忽略了它并始终创建一个新实例。

Since Typescript 2.2 you can access new.target from the constructor. 从Typescript 2.2开始,您可以从构造函数访问new.target

Thus you can make the following call after having called super() : 因此,您可以在调用super()之后进行以下调用:

Object.setPrototypeOf(this, new.target.prototype);

It should solve the propotype chain issue 应该解决原型链问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM