#typescript #generics #static-methods
#typescript #общие #статические методы
Вопрос:
У меня есть следующие базовые и производные классы.
class GenericBase<T = any> {
static method(id: any) {
console.log(`${id}: ${this.name}#method`);
}
public someProp!: T;
}
class DerivedGeneric extends GenericBase<Date> {}
Я ищу способ правильного применения определений типов, который позволит мне вызывать статический метод. Ниже то, что я пробовал до сих пор.
const t1: typeof GenericBase = DerivedGeneric;
t1.method("t1");
type Type<T> = new (...arg: any[]) => T;
const t2: Type<GenericBase> = DerivedGeneric;
t2.method("t2");
Для первого ( t1
) TypeScript показывает следующую ошибку
Тип 'typeof DerivedGeneric' не может быть присвоен типу 'typeof GenericBase'. Тип 'DerivedGeneric' не может быть присвоен типу 'GenericBase'. Типы свойств 'someProp' несовместимы. Тип 'Date' не может быть присвоен типу 'T'.
Для второго он показывает следующую ошибку.
Свойство 'метод' не существует для типа 'Тип>'.
Естественно, следующее работает без какой-либо ошибки во время компиляции…
const t3: Function = DerivedGeneric;
(t3 as typeof DerivedGeneric).method("t3");
… и то же самое происходит со следующим, но теперь у нас ошибка времени выполнения.
const t4: Function = () => {};
(t4 as typeof DerivedGeneric).method("t4");
Без обобщений первый подход ( typeof *Base*
) работает довольно хорошо. Вы можете проверить это по этой ссылке на игровую площадку. Очевидно, что все подходы (кроме t4
) работают во время выполнения, и меня беспокоят только ошибки во время компиляции.
Есть ли какой-либо способ исправить типизацию с помощью общих методов?
Ссылка на игровую площадку
Редактировать: со следующим типом.
type Type<T> = new (...arg: any[]) => T;
type func = Pick<typeof GenericBase, keyof typeof GenericBase> amp; Type<GenericBase>;
Ответ №1:
Проблема в том, что, поскольку базовый класс имеет параметр универсального типа, его конструктор является универсальным конструктором. Вот как будет выглядеть сигнатура конструктора:
const t3 : new <T>(...arg: any[]) => GenericBase<T> = GenericBase
Вот почему, когда вы пытаетесь назначить DerivedGeneric
to typeof GenericBase
, вы не можете, потому что DerivedGeneric
у него нет такого универсального конструктора.
Если вам просто нужен тип, представляющий статику класса, который вы можете использовать Pick
, чтобы избавиться от подписи универсального конструктора из typeof GenericBase
:
const t1: Pick<typeof GenericBase, keyof typeof GenericBase> = DerivedGeneric; // OK
t1.method("t1");
Вы также можете создать пересечение возвратов конструктора GenericBase<any>
и статических членов.
type Type<T> = new (...args: unknown[]) => T;
const t1: Type<GenericBase> amp; Pick<typeof GenericBase, keyof typeof GenericBase> = DerivedGeneric;
t1.method("t1");
new t1()
Примечание: это не будет работать с ...args: any[]
, any
немного особенным, не уверен, как это влияет на это, но unknown
в любом случае следует предпочесть.
Комментарии:
1. Спасибо вам за объяснение. Просто еще один последующий вопрос. О чем ты думаешь
type Type<T> = new (...arg: any[]) => T; type func = Pick<typeof GenericBase, keyof typeof GenericBase> amp; Type<GenericBase>;
? Хотя игровая площадка показывает ошибку, она работает на моей машине 🙂2. @SayanPal Я действительно попробовал это сам и получил ошибку.. не уверен, почему я ожидал, что это сработает как решение для использования как статики, так и не универсального конструктора, но по какой-то причине он выдает ошибку..
3. Обновил вопрос ссылкой на игровую площадку.
4. @SayanPal добавил версию, которая добавляет конструктор обратно в