Назначение обобщенного типа c для производных классов из абстрактного класса с переменными типа в TypeScript - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть абстрактный класс Base, который принимает переменную типа <T> для использования в классе. Затем у меня есть много производных классов, которые явно определяют тип, например class Derived extends Base<string> {...}

Я хочу иметь переменную (или массив переменных), тип которой может быть любым из этих производных классов, независимо от того, что <T> является. Затем я хочу использовать эту переменную для создания новых экземпляров этих производных классов.

Вот некоторый код с тем, что я пробовал. Оттуда я потерялся.

TypeScript Playground link

abstract class Base<T> {
    abstract value: T;
}

class Derived extends Base<string> {
    value = 'Hello world!';
}

class SecondDerived extends Base<number> {
    value = 1234;
}

// This has type (typeof Derived | typeof SecondDerived)
let classes_A = [Derived, SecondDerived];

// This obviously works too, but with many derived classes can get long and tedious
let classes_B: (typeof Derived | typeof SecondDerived)[] = [];
classes_B.push(Derived);
classes_B.push(SecondDerived);

// This does NOT work
let classes_C: Base<any>[] = [];
classes_C.push(Derived); // "typeof Derived is not assignable to type Base<any>"

// This does NOT work
let classes_D: Base<unknown>[] = [];
classes_D.push(Derived); // "typeof Derived is not assignable to type Base<unknown>"

// This does NOT work
let classes_E: Base<string>[] = [];
classes_E.push(Derived); // "typeof Derived is not assignable to type Base<string>"

// This does NOT work
let classes_F: (typeof Base)[] = [];
classes_F.push(Derived); // "typeof Derived is not assignable to typeof Base"

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Мое предложение таково:

let classes: Array<new (...args: any) => Base<any>> = [];
classes.push(Derived); // okay
classes.push(SecondDerived); // okay

Тип элемента массива должен быть «конструктором любого подтипа Base<T> для любого T». Чтобы сказать «конструктор X» как тип, вы используете new подпись , например new () => X. Обратите внимание, что подпись указывает, какие типы и числовые аргументы ожидает конструктор; если вам все равно, то вы можете использовать аргумент отдыха типа any или any[], например new (...args: any) => X.

Поскольку тип, который вы создаете, является любым подтип Base<T> для любого T, и вам, вероятно, не нужно отслеживать какой из них, тогда Base<any>, вероятно, достаточно хорош. (Если нет, то, пожалуйста, опишите случай использования, для которого это не работает).

Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

1 голос
/ 06 февраля 2020

Вам необходимо определить тип для конструктора:

type CtorBase = new () => Base<any>;

Теперь вы можете использовать его для хранения списка конструкторов Base:

let classes_C: CtorBase [] = [];
classes_C.push(Derived);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...