Reputation: 42229
I have some experimental code that inherits from 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();
I've added the clear
method just to illustrate the problem. When this is compiled and run in the browser, I get...
TypeError: array.clear is not a function
How is this completely valid code in TypeScript, but not valid in JavaScript, and is there a way to fix this?
Upvotes: 4
Views: 4040
Reputation: 2969
Since Typescript 2.2 you can access new.target
from the constructor.
Thus you can make the following call after having called super()
:
Object.setPrototypeOf(this, new.target.prototype);
It should solve the propotype chain issue
Upvotes: 0
Reputation: 2462
BTW this is a breaking change in TS2.1
This TS documentation has a recommendation for a changing the prototype in your constructor
constructor(...items) {
super(...items);
Object.setPrototypeOf(this, SuperArray.prototype);
}
Upvotes: 8
Reputation: 164139
Your code compiles into this when targeting 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:
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).
I'll just paste parts of the article Subclassing builtins in ECMAScript 6 which explains why it can't be done with es5
:
Allocation obstacle: MyArray allocates the wrong kind of object
Array instances are special – the ECMAScript 6 specification calls them exotic. Their handling of the property length can’t be replicated via normal JavaScript. If you invoke the constructor MyArray then an instance of MyArray is created, not an exotic object.Initialization obstacle: MyArray can’t use Array for initialization
It is impossible to hand an existing object to Array via this – it completely ignores its this and always creates a new instance.
Upvotes: 2