Class extended from built-in Array in Typescript 1.6.2 does not update length while using [] operator
Asked Answered
L

2

3

it should be possible to extend build-in types in ts 1.6 as I read here:

TypeScript 1.6 adds support for classes extending arbitrary expression that computes a constructor function. This means that built-in types can now be extended in class declarations.

...

Some examples:

// Extend built-in types

class MyArray extends Array<number> { }
class MyError extends Error { }

...

However when extending Array, length property is not updated while using [] operator to set values. Push function works fine, but I need [] operator.

My Example:

class ExtendedArray<T> extends Array<T> {}

var buildinArray = new Array<string>();
var extendedArray = new ExtendedArray<string>();

buildinArray.push("A");
console.log(buildinArray.length); // 1 - OK
buildinArray[2] = "B";
console.log(buildinArray.length); // 3 - OK

extendedArray.push("A");
console.log(extendedArray.length); // 1 - OK
extendedArray[2] = "B";
console.log(extendedArray.length); // 1 - FAIL
console.dir(extendedArray); // both values, but wrong length

Am I doing something wrong? Where is the problem?

Leipzig answered 26/11, 2015 at 22:29 Comment(1)
What's your use case for extending Array? I've never felt the need to subclass arrays especially in TypeScript where the interfaces are extremely versatile when it comes to generics.Ind
A
5

Your code translates to this JavaScript code:

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var ExtendedArray = (function (_super) {
    __extends(ExtendedArray, _super);
    function ExtendedArray() {
        _super.apply(this, arguments);
    }
    return ExtendedArray;
})(Array);
var buildinArray = new Array();
var extendedArray = new ExtendedArray();
buildinArray.push("A");
console.log(buildinArray.length); // 1 - OK
buildinArray[2] = "B";
console.log(buildinArray.length); // 3 - OK
extendedArray.push("A");
console.log(extendedArray.length); // 1 - OK
extendedArray[2] = "B";
console.log(extendedArray.length); // 1 - FAIL
console.dir(extendedArray); // both values, but wrong length

[Playground]

The problem is that the bracket notation is not copied as part of copying of Array prototype:

In JavaScript, we can sub-class native data types by extending the native prototypes. This works perfectly with the native String object; but, when it comes to native Arrays, things don't work quite so nicely. If we extend the Array prototype, we inherit the native array functions; but, we no longer have the ability to use bracket notation to set and get indexed values within the given array. Sure, we can use push() and pop() to overcome this limitation; but, if we want to keep the bracket notation feature functional, we have to build on top of an existing array instance rather than truly sub-classing the Array object.

[Source]

There is an in-depth discussion and solutions here by Dr. Axel Rauschmayer.

Analog answered 27/11, 2015 at 7:23 Comment(0)
I
1

Extending Array is only supported in ES6 environments, so if you've set the compilerSettings.target of your tsconfig.json to ES3 or ES5 this won't work properly. There are workarounds in ES5 but I'd say it isn't worth the trouble - although you can probably use it in TypeScript since it is a superset of ES5. This book on ES6 explains the situation in more detail.

Ind answered 27/11, 2015 at 7:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.