5

while playing around with typescript I ran into then following interesting behavior:

class ExtArray<U> extends Array<U> {

    constructor(...args : U[]) {
        super(...args);
    }

    public contains(element : U) : boolean {
        var i = this.indexOf(element);
        return i !== -1;
    }
}


var test : ExtArray<string> = new ExtArray("a", "b", "c");

test.push("y");

console.log(test.length); // 1

console.log(test[0]);  // y
console.log(test[1]);  // undefined
console.log("Has a: " + test.contains("a"));  // Has a: false
console.log("Has y: " + test.contains("y"));  // Has y : true

I've added the output of the console.log statements as comments. See this typescript playground for an executable example and the javascript code.

As you can see it seems as if the elements passed to the constructor are not added to the array.

The section about extending expression in Whats new in Typescript suggests that it should be possible to extend the native Array type like that in typescript 1.6. Also I didn't find anything in the typescript language reference, that explains this behavior.

Most of the other questions about extending Arrays I found here are at least one year old and usually talk about a pre-1.0 version of typescript and therefore suggest to set up the prototype chain directly.

I seriously don't see what is going wrong here and I'm starting to suspect a typescript bug. Or at least some kind of undocumented restriction for extending Arrays.

What goes wrong here?

Cœur
  • 37,241
  • 25
  • 195
  • 267

1 Answers1

2

It's a little easier to understand what's going on if you JSON.stringify() your object:

var test : ExtArray<string> = new ExtArray("a", "b", "c");
test.push("y");

// outputs {"0":"y","length":1}
document.writeln(JSON.stringify(test)); 

If you instead new-up a native Array, the resulting object is quite a bit different:

var test : Array<string> = new Array("a", "b", "c");
test.push("y");

// outputs ["a","b","c","y"]
document.writeln(JSON.stringify(test));

I agree with you that the documentation seems to imply that the subclass's constructor should behave the way you're expecting. Even stranger, I seem to get inconsistent results when testing whether or not the subclass is an Array using the methods described here:

test.constructor === Array // false
test instanceof Array // true
Array.isArray(test) // false

I would suggest opening an issue on the TypeScript GitHub repository. Even if this is the expected behavior, the official documentation is misleading and should clarify what exactly is expected when native objects are subclassed.

Community
  • 1
  • 1
Nathan Friend
  • 12,155
  • 10
  • 75
  • 125
  • 1
    Thanks for the answer I already noticed that the extended array is more an object than an array, but I didn't think it mattered (since an array can also be seen as an object having numbers as property names). Also I think it's odd that push still works on an object like data structure. I'll file a bug. –  Mar 01 '16 at 18:11
  • 1
    @LongHairedHacker Cool, can you post a link to the issue once you create it? I'm interested in how it will be resolved. – Nathan Friend Mar 01 '16 at 18:23