Instantiating an abstract-derived class by its typ

2019-08-08 01:29发布

I'm writing some graphing code in TypeScript 2.6, and I'm have a small obstacle with respect to inheritance and generic code:

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());
  }
}

I intended the code above to construct a new object that is derived from Series, where the constructor on the last line comes from a runtime-assigned type value. The problem I have is that Series is abstract, so I cannot instantiate it, however I will never assign the value typeof Series to the series variable. (But TypeScript doesn't know that).

I have thought of a few solutions, but none of them are especially elegant. One is to simply remove the abstract modifier from Series and optionally put in some code to throw an exception if it's instantiated. Another solution is to change the definition of seriesType to:

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

but then I need to maintain this list every time I add a new type of series. I know I can do, for example:

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

and then

let seriesType: DerivedSeries = null;

but this is not much of an improvement, if at all.

Is there any more elegant way I can tell TypeScript that seriesType is of type Series, but must also be of an instantiable child type? i.e. the expression seriesType = Series; should throw a compile-time error, not new seriesType();.

Thanks

1条回答
做个烂人
2楼-- · 2019-08-08 02:14

The simplest way to instantiate classes derived from an abstract class is by defining an object type with the new() method:

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();
}
查看更多
登录 后发表回答