Общий класс TypeScript, который создает экземпляры класса его переменной типа? - PullRequest
0 голосов
/ 11 мая 2018

Я знаком с общими классами в TypeScript, где класс может быть определен с помощью переменной связанного типа, а затем экземпляры с определенным типом могут манипулировать и возвращать значения этого типа.

Проблема: Iнужен универсальный класс, который создает экземпляров переменной типа.Например:

class Thing {
  thingProp: string;
}

class ThingOne extends Thing {
  thingOneProp: string;
}

class ThingTwo extends Thing {
  thingTwoProp: string;
}

class Maker<T extends Thing> {

  make(): T {
    return new T();
    //         ^--- " // <- "error TS2304: Cannot find name 'T'""
  }

}

let thingOneMaker = new Maker<ThingOne>();

let thingOne: ThingOne = thingOneMaker.make();

let thingTwoMaker = new Maker<ThingTwo>();

let thingTwo: ThingTwo = thingTwoMaker.make();

let thingError: ThingOne = thingTwoMaker.make();
//      ^--- "error TS2322: Type 'ThingTwo' is not assignable to type 'ThingOne'"

Кажется, это почти работает.Компилятор генерирует код, и ошибка в последней строке показывает, что TypeScript понимает, какой тип thingTwoMaker.make() должен возвращаться.

Однако ошибка на return new T(); показывает, что TypeScript не понимает, что я пытаюсьчтобы создать экземпляры класса переменной типа, и сгенерированный JavaScript подтверждает это:

var Maker = (function () {
    function Maker() {
    }
    Maker.prototype.make = function () {
        return new T(); // <- "error TS2304: Cannot find name 'T'"
    };
    return Maker;
}());

И, что неудивительно, запуск сгенерированного JavaScript с Node.js приводит к ошибке ReferenceError: T is not defined.

Как я могу создать универсальный класс, экземпляры которого могут создавать экземпляров класса переменной типа?(Протестировано с использованием TypeScript 2.0.10.)

1 Ответ

0 голосов
/ 11 мая 2018

Каким-то образом вам нужно дать классу Maker конструктор того типа, который вы хотите сделать, чтобы у него было значение для вызова new.

.скажем, хорошим вариантом будет передать конструктор класса в качестве аргумента конструктору Maker.Это позволит ему создавать экземпляры этого класса и автоматически выводит тип, который он создает, поэтому вам больше не нужно вручную аннотировать универсальный тип.

Так что может быть что-то вроде этого:

class Maker<T extends Thing> {

  private ctor: {new(): T};

  constructor(ctor: {new(): T}) {
    this.ctor = ctor;
  }

  make(): T {
    return new this.ctor();
  }
}

Затем вы можете передать правильный конструктор класса каждому виду Maker, и тип будет автоматически выведен:

let thingOneMaker = new Maker(ThingOne);
let thingOne: ThingOne = thingOneMaker.make();

let thingTwoMaker = new Maker(ThingTwo);
let thingTwo: ThingTwo = thingTwoMaker.make();

// Still an error.
let thingError: ThingOne = thingTwoMaker.make();

Ссылка на игровую площадку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...