У меня есть экспериментальный код, который наследуется от 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();

Детская площадка

Я добавил метод clear просто для иллюстрации проблемы. Когда это скомпилировано и запущено в браузере, я получаю ...

Ошибка типа: array.clear не является функцией

Как этот полностью допустимый код в TypeScript, но не действительный в JavaScript, и есть ли способ это исправить?

2
Matthew Layton 11 Янв 2017 в 17:04

3 ответа

Лучший ответ

Кстати, это серьезное изменение в TS2.1

Это в документации TS есть рекомендации по изменению прототипа в вашем конструкторе

constructor(...items) {
    super(...items);
    Object.setPrototypeOf(this, SuperArray.prototype);
}
6
HolgerJeromin 11 Янв 2017 в 15:10

Начиная с Typescript 2.2 вы можете получить доступ к new.target из конструктора.

Таким образом, вы можете сделать следующий вызов после вызова super():

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

Это должно решить проблему цепи прототипа

0
Serge Intern 3 Май 2017 в 09:38

Ваш код компилируется в это при нацеливании 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();

Невозможно расширить собственные объекты, как это, поэтому вы получаете эту ошибку.
Если вы выберете 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();

И это будет прекрасно работать (если вы запускаете его в браузере, который поддерживает классы es6).


Редактировать

Я просто вставлю фрагменты статьи Встроенные средства создания подклассов в ECMAScript 6 который объясняет, почему это нельзя сделать с es5:

Препятствие для размещения: MyArray выделяет неправильный тип объекта
Экземпляры массива особенные - спецификация ECMAScript 6 вызывает их экзотика. Их обработка длины свойства не может быть воспроизведена через обычный JavaScript. Если вы вызываете конструктор MyArray, то Экземпляр MyArray создан, а не экзотический объект.

Препятствие инициализации: MyArray не может использовать массив для инициализации
Невозможно передать существующий объект в массив через это - это полностью игнорирует это и всегда создает новый экземпляр.

2
Nitzan Tomer 11 Янв 2017 в 14:49