# C# List<T> Class to TypeScript extends Array<T>

After programming in C# for almost 19 years, I've decided to try my hand at TypeScript. Still thinking Object Oriented Programming concepts and C#, I've run into a few doozies I thought I'd document.

I tried extending my custom class from a `List<T>` with `T` being a custom class.

## My C# Class

Below is my `Team` class in C#. At runtime, I expect to get a count of 2 for the number of enabled team members with my sample dataset.

```csharp
public class Team: List<TeamMember> {

    public Team(List<List<string>> rows) {
		this.AddRange(rows.Where(x => !string.IsNullOrEmpty(x[0]))
          .Select(x => new TeamMember(x)));
    }

    public List<TeamMember> getEnabledUsers() {
        return this.FindAll(member => member.enabled);
    }
}
```

You can see a complete working sample in [this fiddle](https://dotnetfiddle.net/cRFaD8).

<iframe width="100%" height="400" src="https://dotnetfiddle.net/Widget?Languages=CSharp&CSharp_FiddleId=uCZE2u" frameborder="0"></iframe>


## TypeScript with a runtime error

I converted that C# class to a TypeScript class. This `Team` class compiles without any issues. But if you run it on [TypeScript 
 playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEAqCmYC2BZeSBG8BO0DeAsAFDSnQB2y8AXNBAC7YCW5A5gNzFnTyUYjwAJrQwB7UQLDlORLmWCjyDbAFdg9UdgAU2UQHcAamBAr4EWspasA2gF0AlPjndS9ABZMIAOkpJ40AF5oXUNjUwhrAAZbGRcyd08vXjB+IUDg-SMTM2sARlsvDQAZfRwAYUh4LUcA2ugAIgBPM3rYsgBfYk7ZIlBIGARkHgAPel5BGABBbGwwRoAeQdR0LGwAPice7gUlRjUNbRDzaGnZhdO5+cs2NbXHQhI4uhUABxxqtrijrwAzJhAxod9IENiEorZoABCIL1er2ZxPUheJBgF46YEBDYJbwvFQQNxacjwPRwRDLTDvEL2amfaDdBGseD0ACifAEggAqhAcBBqtBaBcFks0BT1ptEQB6CVwAASAEkAMrQADqAHkAEoAaSVAFpgkyVNhyNBVRgAFbwdReABuYTMWmx9l+-0BWj8opB0HdqySbKE9lp3GwBqN0GxzoB729OE90ewvpS7IDCO69JIAno0EEYHoYHS1ms9WV-wginqABoGgBNFq2csIxHcQsKxTkRoV6u1+uPRsuQuTFSCYPtyv1AByonqdYbveghY7sNsMWIGbDZNy6SJJKWWmzueTPVXY2QACZ0sekLkvIyWX7OdzsLyD8QdqWBF4QKJWFp6tYLyeP14Vh3AhBU3FEFQQEEfV6ENY0AJOdQVGMaBbWyWh6mgABqNdT0Ath3ADIA), you will see a runtime error.


```javascript
...
class Team extends Array<TeamMember> {

    constructor(rows: Array<Array<string>>) {
        super();
        rows.filter(row => row[0] != "")
            .map(row => this.push(new TeamMember(row)));
    }

    getEnabledUsers() : Array<TeamMember> {
        return this.filter(member => member.enabled);
    }
}
...
```

### Misleading runtime error

The error on the playground or even if you run it locally says:

> [ERR]: "Executed JavaScript Failed:" 

> [ERR]: rows.filter is not a function 

So that means that I have done something wrong in the constructor where `rows.filter` is. Trying to debug what happens in the constructor made me waste a few hours on a Sunday.

But, if I take away the `getEnabledUsers()` method, this error goes away. 🤯

Reading through multiple SO questions and blogs etc finally led me to `Object.values`. The [Object.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values) method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop.

## TypeScript which works

`Object.values` allowed me to reference `this` as an array in my `Team` class. So I changed `return this.filter(member => member.enabled);` to `return Object.values(this).filter(member => member.enabled);`. This made my code work at Runtime and gave me the necessary output as seen in this [playground link](https://www.typescriptlang.org/play?#code/MYGwhgzhAEAqCmYC2BZeSBG8BO0DeAsAFDSnQB2y8AXNBAC7YCW5A5gNzFnTyUYjwAJrQwB7UQLDlORLmWCjyDbAFdg9UdgAU2UQHcAamBAr4EWspasA2gF0AlPjndS9ABZMIAOkpJ40AF5oXUNjUwhrAAZbGRcyd08vXjB+IUDg-SMTM2sARlsvDQAZfRwAYUh4LUcA2ugAIgBPM3rYsgBfYk7ZIlBIGARkHgAPel5BGABBbGwwRoAeQdR0LGwAPice7gUlRjUNbRDzaGnZhdO5+cs2NbXHQhI4uhUABxxqtrijrwAzJhAxod9IENiEorZoABCIL1er2ZxPUheJBgF46YEBDYJbwvFQQNxacjwPRwRDLTDvEL2amfaDdBGseD0ACifAEggAqhAcBBqtBaBcFks0BT1ptEdgmSpsORoAB5DAAK3g6i8ADcwmYtNj7L9-oCtH5RSDoEbVkk2UJ7LTuAB6W1wAASAEkAMrQAAicuZ7oAcnLYNAAOpygBKAGloABaYJSmXQbF6gHvM04E2p7AWlLs60I7r0kgCejQQRgehgdLWaz1IP-CCKeoAGgaAE0WrZGwjEdxq67FORGk3W+3O49uy5q5MVIJJYPm-VfaJ6h2u+PoNWh7DbDFiEWE2TcukiSSllpS+Xcz092NkAAmdI3pC5LyMlmWznc7C8y-EHb1gReCAoisFo9TWI+t6AbwrDuBCrpuKIKggIIsb0NKsqQSc6gqMY0AatktD1NAADU+53lBbDuNaQA).

Here's the `Team` class for comparison

```javascript
...
class Team extends Array<TeamMember> {

    constructor(rows: Array<Array<string>>) {
        super();
        rows.filter(row => row[0] != "")
            .map(row => this.push(new TeamMember(row)));
    }

    getEnabledUsers() : Array<TeamMember> {
        return Object.values(this).filter(member => member.enabled);
    }
}
...
```

### Is using `Object.values()` the correct thing to do?

Yes, using `Object.values()` fixed the runtime error. But it was extra computation and memory utilised to create an array from an already existing array. So IMHO, it seems like doubling the work.


### What's the real error?

Thanks to my colleague Ynze who tracked down this FAQ answer from Microsoft on ["Why doesn't extending built-ins like Error, Array, and Map work?"](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-doesnt-extending-built-ins-like-error-array-and-map-work).

So essentially, it's not supported in TypeScript for now due to how an `Array` for example uses ECMAScript 6's `new.target` to adjust the prototype chain.

## TypeScript - Best Practice?

Speaking with another front-end developer colleague Ben resulted in him sharing the following code as better way of defining this `Team` class. You can see a working version on this [playground link](https://www.typescriptlang.org/play?#code/MYGwhgzhAEAqCmYC2BZeSBG8BO0DeAsAFDSnQB2y8AXNBAC7YCW5A5gNzFnTyUYjwAJrQwB7UQLDlORLmWCjyDbAFdg9UdgAU2UQHcAamBAr4EWspasA2gF0AlPjndS9ABZMIAOkpJ40AF5oXUNjUwhrAAZbGRcyd08vXjB+IUDg-SMTM2sARlsvDQAZfRwAYUh4LUcA2ugAIgBPM3rYsgBfYk7ZIlBIGARkJx7uP0wcGCDyeD1oAEFsbDBGgB5B1HQsbAA+aplnaAUlRjUNbRDzecXllYWl1cs2be3HQhI4jL1vADMmEHocDp9IFtp8orZoABCIL1er2A4faBeJBgAAOQNmAVBCW8Yy23lRKggbi001m6zQ43O+nstLapG6B1Y8HoAFE+AJBABVCATarQWh3G4UzY4UFvRHYFkqbDkaA45Gi7A-P4A7R4nAg6Aa7BJDlCez06DdRkkAT0aCCMD0MDpazWeoAdT+EEU9QANA0AJotWzuhGIsgOgDKinIjQ93t9-vegZcDrmKkEUojnvqADlRPU-QG4w7I7DbDFiOb5YgkLl0mS4OWtFabYbiCWWWXkAAmdIA5C5LzMtn67m85V7Ju9RSugReECiVhaerWLtINtT3isdwQ4NuUQqECCYLS2XQZfzdQqYzQABuYRoDWgAGpW0uV2x3IagA).

```javascript
...
class Team {

    members = new Array<TeamMember>();

    constructor(rows: Array<Array<string>>) {
        rows.filter(row => row[0] != "")
            .map(row => this.members.push(new TeamMember(row)));
    }

    getEnabledUsers() : Array<TeamMember> {
        return this.members.filter(member => member.enabled);
    }
}
...
```

## Verdict

TypeScript is not like C#. So proceed with caution 😉
Hopefully this article will help the next TypeScript noob!
