1

I would like to make a new class that derives from Array that has its own methods in addition to the regular array methods.

export class ObjectCollection<T extends Iidentifier> extends Array<T> {

  constructor(collection: T[] = []) {
    super(...collection);
  }

  // used for getting instance from a collection of objects
  public getInstance(id: Id) {
    return this.find(item => item.Id.toString() === id.toString()) || new 
    Array<T>();
  }

}

I have also have child classes that inherit from that class.

export class TargetCategories extends ObjectCollection<TargetCategory> {

  constructor(categories: TargetCategory[] = []) {
    super(categories);
  }

  public getCategoryType(id: Iidentifier): string {
    return this[id].Category.length < 2 ? "dummy" : "saved";
  }

}

When I instantiate a TargetCategories object, I'm only able to use methods that are in array though. I'm not able to call things like getCategoryType and getInstance.

2 Answers2

-1

I have put it all together, fixed minor bugs and it seems ok.

type Id = number;
interface Iidentifier {
    Id: number;
}

class ObjectCollection<T extends Iidentifier> extends Array<T> {

  constructor(collection: T[] = []) {
    super(...collection);
  }

  // used for getting instance from a collection of objects
  public getInstance(id: Id) {
    return this.find(item => item.Id.toString() === id.toString()) || new 
    Array<T>();
  }

}

interface TargetCategory extends Iidentifier {
    Category: number[];
}

class TargetCategories extends ObjectCollection<TargetCategory> {

  constructor(categories: TargetCategory[] = []) {
    super(categories);
  }

  public getCategoryType(id: Iidentifier): string {
    return this[id.Id].Category.length < 2 ? "dummy" : "saved";
  }
}

let tc = new TargetCategories();
tc.getInstance(1);
tc.getCategoryType({ Id: 2 });
Rodris
  • 2,603
  • 1
  • 17
  • 25
  • Do not extend `Array` your code will break hard depending on how it is transpiled and in which JavaScript runtime it is executed. This is a failure of the standards body to create a good migration path to ES2015. There is no reliable way to do this at the current time. – Aluan Haddad Sep 08 '17 at 02:19
  • @AluanHaddad Does it mean that, depending, it may work? And how about to completely wrap the array? It would give some work, but wouldn't it be reliable? `class MyArray implements Array { private _array: Array; }` – Rodris Sep 08 '17 at 04:41
  • Yes it may work and it may fail... it is a sad state of affairs. Wrapping is conceptually the right approach but there is no way, AFAIK, to intercept the property access for numeric values without using a proxy, another ES2015 feature. The whole thing is a mess. – Aluan Haddad Sep 08 '17 at 05:49
  • @AluanHaddad I don't understand you. What is the problem with `get length(): number { return this._array.length; }`? – Rodris Sep 08 '17 at 10:59
  • nothing at all. I just meant that you won't be able to use bracket notation on the wrapper. `a[i]` will not work. If you do not need that notation, then wrapping an Array is definitely the way to go. – Aluan Haddad Sep 08 '17 at 11:11
  • @AluanHaddad Would you be able to assist me in setting up a proxy class? https://stackoverflow.com/questions/46123916/conditionally-calling-property-methods-on-classes – Stuart Seupaul Sep 08 '17 at 20:29
  • The proxy is just to get the index operation `a[i]` to work, if all you need is map and filter and whatnot, then there are easier approaches. – Aluan Haddad Sep 08 '17 at 20:35
-1

I found a way for it to work, but I doubt it's the only way, or cleanest way.

interface IDifferentArray {
    id: string | number;
}

export class DifferentArray<T extends IDifferentArray> extends Array<T> {

    public lengthMessage: () => void;
    public otherMethod: () => number;

    constructor(items: Array<T> = []) {
        super(...items);

        this.lengthMessage = function() {
            return `My length is ${this.length}`;
        }

        this.otherMethod = function() {
            return 12;
        }
    }
}

You can access native array methods, properties, and add your own instance methods. If you put it outside the constructor, it will be a class method.

That's the way it works in regular javascript. I thought es6/typescript would emulate real OOP, but guess not.

  • It has nothing to do with OOP and everything to do with extending specific built-in types such as a `Array` which have certain behaviors which make transpilation to ES5 problematic. Also, if you're trying to write code the you would in Java then you're wasting your time. – Aluan Haddad Sep 08 '17 at 02:22