arv - Instantiering af en abstrakt-afledt klasse ved dens typenavn i TypeScript


Jeg skriver noget grafkode i TypeScript 2.6, og jeg har en lille forhindring med hensyn til arv og generisk kode:

abstract class Series { /**/ }

class LineSeries    extends Series { /**/ }
class BarSeries     extends Series { /**/ }
class ScatterSeries extends Series { /**/ }

class Chart {
  private seriesArray: Series[] = [];

  constructor(series: Series[]) {
    let seriesType: typeof Series = null;

    switch (series.SeriesType) {
      case SeriesType.LineSeries:
        seriesType = LineSeries;
        break;
      case SeriesType.BarSeries:
        seriesType = BarSeries;
        break;
      case SeriesType.ScatterSeries:
        seriesType = ScatterSeries;
        break;
      default:
        throw "Unsupported series type";
    }

    for (let i = 0; i < series.length; i++)
      this.SeriesArray.push(new seriesType());
  }
}

Jeg havde til hensigt, at koden ovenfor skulle konstruere et nyt objekt, der er afledt af Series, hvor konstruktøren på den sidste linje kommer fra en runtime-tildelt typeværdi. Problemet jeg har er, at Series er abstrakt, så jeg kan ikke instantierer den, men jeg vil aldrig tildele værdien typeof Series til series-variablen. (Men TypeScript ved ikke det).

Jeg har tænkt på nogle få løsninger, men ingen af dem er særligt elegante. Én mulighed er blot at fjerne abstract-modifikatoren fra Series og eventuelt indsætte noget kode for at kaste en undtagelse, hvis den bliver instansieret. En anden løsning er at ændre definitionen af seriesType til:

let seriesType: (typeof LineSeries | typeof BarSeries | typeof ScatterSeries) = null;

men så bliver jeg nødt til at opdatere denne liste hver gang, jeg tilføjer en ny type serie. Jeg ved, jeg kan gøre for eksempel:

type DerivedSeries = (typeof LineSeries | typeof BarSeries | typeof ScatterSeries);

og så

let seriesType: DerivedSeries = null;

men dette er ikke nogen stor forbedring, hvis overhovedet.

Er der en mere elegant måde, jeg kan fortælle TypeScript, at seriesType er af typen Series, men også skal være af en instantiérbar børnetype? Dvs. udtrykket seriesType=Series; bør give en compile-time fejl, ikke new seriesType();.

Tak

Svar #1

Den enkleste måde at instantisere klasser, der er afledt af en abstrakt klasse, er ved at definere en objekttype med new()-metoden:

abstract class AbstractClass { /**/ }

class DerivedClassA extends AbstractClass { /**/ }
class DerivedClassB extends AbstractClass { /**/ }

const classCtors: Array<{ new(): AbstractClass }> = [
    DerivedClassA,
    DerivedClassB
];

for (const ctor of classCtors) {
    const instance = new ctor();
}

Relaterede artikler