javascript - Hur implementerar man en array-liknande klass med egna metoder med Typescript?


Jag vill implementera en array-liknande klass som:

  1. accepterar array som konstruktörens parameter
  2. ska vara itererbar och ha alla inbyggda array-metoder
  3. ha några egna metoder
  4. Bör kunna utöka en annan klass

Jag ser det så här:

class BaseModel {
  arr: Array;

  constructor(arr: Array<any>) { // <= req. #1
    this.arr = arr;
  }

  serialize(arr) { // <= req. #3
    this.arr = arr;
  }
}

class ListModel extends BaseModel { // <= req. #4
  constructor(arr: Array<any>) { // <= req. #1
    super(arr);
  }

  sayHello() { // <= req. #3
    console.log('hello');
  }
}

let list = new ListModel([1,2,3]);
list.sayHello();
// expected output:
// 'hello'
list.push(4); // <= req. #2

for (let a of list) { // <= req. #2
  console.log(a);
}
// expected output:
// 1
// 2
// 3
// 4
list.serialize([2,3]);

for (let a of list) {
  console.log(a);
}
// expected output:
// 2
// 3

Är det möjligt med TypeScript? Jag har letat efter en lösning men har inte hittat något som kommer närmare dessa krav. Tack!

Svar #1

Du kan utöka Array-klassen och genom att göra det uppfylla krav #2.
Här är en implementering som jag tror motsvarar alla dina krav:

class MyArray<T> extends Array<T> {
    constructor(items?: T[]) {
        super();
        items && this.addItems(items);
    }

    public serialize(items: T[]): void {
        this.splice(0, this.length);
        this.addItems(items);
    }

    private addItems(items: T[]) {
        items.forEach(item => this.push(item));
    }
}

class StringsList extends MyArray<string> {
    public sayHello(): void { // req. #3
        console.log("hello");
    }
}

class NumbersList extends MyArray<number> {
    public sum(): number { // req. #3
        return this.reduce((prev: number, current: number) => prev + current);
    }
}

Om du inte gillar generics-delen kan du helt enkelt utöka Array<any>.

Exempel :

let arr1 = new MyArray(["hey", 4, true]);
console.log(arr1); // ["hey", 4, true]

arr1.push(99);
console.log(arr1); // ["hey", 4, true, 99]

arr1.forEach(item => console.log(item)); // hey, 4, true, 99

let arr2 = new StringsList(["str1", "str2"]);
console.log(arr2); // ["str1", "str2"]

arr2.serialize(["str3", "str4"]);
console.log(arr2); // ["str3", "str4"]

let arr3 = new NumbersList([1,2,3,4,5]);
console.log(arr3.sum()); // 15

Svar #2

Det verkar som att det är ett nej-nej att utöka Arrays i Typescript, jag fick körtidsfel och jag hittade denna utmärkta artikel för att göra det på rätt sätt: https://blog.simontest.net/extend-array-with-typescript-965cc1134b3

Våra instanser av anpassade klasser behöver skapas som en Singleton för att tilldela rätt prototyp och inte ärva Array-prototypen vid körning:

export class MyArray<T> extends Array<any> {

  static create<T>(): MyArray<T> {
    return Object.create(MyArray.prototype);
  }

  ...
}

Utan detta finns de anpassade metoderna inte för JavaScript vid körning.

Relaterade artiklar