Насколько я могу судить, мы можем свести ваш вопрос к следующему. Учитывая иерархию классов с некоторыми свойствами stati c:
class BaseClass {
public static staticPropBase: string = 'foo';
}
class SubClass extends BaseClass {
public static staticPropSub: string = 'bar';
}
Как мы можем получить доступ к этим свойствам stati c из экземпляров класса? Во время выполнения это на самом деле просто; все JavaScript объекты имеют свойство constructor
, которое ссылается на функцию конструктора, которая его создала. Таким образом, (new SubClass()).constructor
будет SubClass
со всеми его свойствами c.
Таким образом, вы можете написать это, и это будет работать:
const subclass = new SubClass();
console.log(subclass.constructor.staticPropBase); // TS error, but "foo" at runtime
console.log(subclass.constructor.staticPropSub); // TS error, but "bar" at rntime
Но проблема в том, что компилятор TypeScript несчастен. Он не понимает, что subclass.constructor
является конструктором SubClass
. Все, что он знает о subclass.constructor
, это то, что это Function
. Это правда (конструкторы класса являются функциями), но не указывают c достаточно, чтобы быть полезным.
Но подождите, разве компилятор TypeScript не должен знать , что тип (new SubClass()).constructor
- это typeof SubClass
само по себе? Да, вероятно ... и это давняя открытая проблема, см. Microsoft / TypeScript # 3841 . Заявленная причина , почему это не делается автоматически, заключается в том, что конструкторы подклассов не обязаны быть действительными подтипами своих конструкторов суперкласса. В следующем сценарии:
class A {
a: string = "a";
constructor() { } // no param
}
class B extends A {
b: number;
constructor(b: number) { // one param
super();
this.b = b;
}
}
, хотя тип экземпляра B
является подтипом типа экземпляра A
, его конструктор typeof B
является , а не подтипом typeof A
(поскольку конструктор B
требует аргумент, а A
- нет):
const a: A = new B(123); // okay
const _A: typeof A = B; // error! Type 'typeof B' is not assignable to type 'typeof A'.(2322)
Если компилятор TypeScript автоматически предоставил A
constructor
свойство типа typeof A
и B
a constructor
свойство типа typeof B
, тогда типы экземпляров B
больше не будут действительным подтипом A
, и модель подтипа extends
не будет работать.
Blecch. Было бы неплохо, если бы TS мог сделать что-то лучше, чем Function
. Но даже если они в конце концов внесут изменения, у вас есть проблема сегодня . Что вы можете сделать сейчас?
Вероятно, лучшим текущим решением является ручное объявление о том, что экземпляры вашего класса имеют свойство constructor
правильного типа. Поскольку ваши конструкторы классов пусты, typeof SubClass
является допустимым подтипом typeof BaseClass
, поэтому вышеупомянутая проблема не возникает. (Если это произойдет, вы, вероятно, могли бы использовать такой тип, как Pick<typeof SubClass, keyof typeof SubClass>
, чтобы сохранить свойства stati c, но игнорировать сигнатуру конструктора. Дополнительная информация доступна по запросу.)
Объявление немного странное , но выглядит это так:
class BaseClass {
declare ["constructor"]: typeof BaseClass; // TS 3.7+
//["constructor"]!: typeof BaseClass; // TS 3.6-
public static staticPropBase: string = 'foo';
}
class SubClass extends BaseClass {
declare ["constructor"]: typeof SubClass; // TS 3.7+
//["constructor"]!: typeof SubClass; // TS 3.6-
public static staticPropSub: string = 'bar';
}
(Обратите внимание, что для TS3.7 и выше вы должны использовать a declare
модификатор свойства , тогда как для TS2.7 - TS3.6 Вы должны использовать утверждение определенного присваивания . Они в основном делают одно и то же. Больше информации по запросу.)
И теперь просто работает следующее:
const subclass = new SubClass();
console.log(subclass.constructor.staticPropBase); // okay, "foo"
console.log(subclass.constructor.staticPropSub); // okay, "bar"
В противном случае вы всегда можете просто использовать утверждения типа для подавления предупреждений компилятора:
console.log((subclass.constructor as typeof SubClass).staticPropBase); // okay, "foo"
console.log((subclass.constructor as typeof SubClass).staticPropSub); // okay, "bar"
Лично я бы довольно сильно ввел определение класса, но утверждения типа также будут работать.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код