#typescript
Вопрос:
В настоящее время я натыкаюсь на стену в машинописном тексте.
В принципе, я хочу вызвать статическую функцию из класса, расширяющего определенный абстрактный класс.
Я получаю следующую ошибку
The 'this' context of type 'typeof A' is not assignable to method's 'this' of type 'AStatic<AStatic<unknown>>'. Cannot assign an abstract constructor type to a non-abstract constructor type.
Вот ссылка на игровую площадку с машинописным текстом
Вот код:
type AStatic<S extends A> = { new(): S };
abstract class A {
static callStatic<S extends AStatic<S>>(this: AStatic<S>) {
console.log('hey')
}
}
class B extends A {
}
class D extends A {
}
class C {
aType: typeof A;
constructor(type: typeof A) {
this.aType = type;
this.aType.callStatic(); // error is here
}
}
const c = new C(B);
const c_2 = new C(D);
Единственный способ, которым мне удалось встроить его в typescript, — это передать any
как вместо typeof A
. Это просто позор, потому что я не получаю поддержки от своей среды разработки для функций A.
Обратите внимание, что у меня нет контроля над классом A и типом AStatic, так как они взяты из внешней библиотеки.
Комментарии:
1. @ConnorLow Вы имеете
this
в виду, что передается в качестве параметра статической функции? Если это так, как я уже сказал, я не могу контролировать определение функции, так как оно находится во внешней библиотеке. У меня есть контроль только над классами B, C и D2. Я беру свои слова обратно. Я вижу, что вы
typeof A
не используетеA
. Совершенно другой сенарио.
Ответ №1:
Ты уже близко! Взгляните на свое псевдо-определение для A
:
abstract class A {
static callStatic<S extends AStatic<S>>(this: AStatic<S>) {
// ^^^^^^^^^^^^^^^^
// the `this` parameter must be type AStatic<A>
И глядя на AStatic
:
type AStatic<S extends A> = { new(): A };
// ^^^^^ - type must have a constructor,
// which rules out abstract classes.
Это исключает typeof A
в качестве this
параметра, так как это так abstract
. Мы могли бы попробовать использовать AStatic
напрямую:
class C {
aType: AStatic<A>;
constructor(type: AStatic<A>) {
this.aType = type;
this.aType.callStatic();
// ^^^^^^^^^^ - Property 'callStatic' does not exist on type 'AStatic<A>'
}
}
Но callStatic
не определено вкл AStatic
. Решение представляет собой тип пересечения:
class C {
aType: AStatic<A> amp; typeof A
constructor(type: AStatic<A> amp; typeof A) {
this.aType = type;
this.aType.callStatic() // works!
}
}
Как отметил Мансман, однако, если вы не переопределите callStatic
свои производные типы, вам вообще не нужно передавать typeof A
:
const c = new C(B);
c.callStatic(); // hey
B.callStatic(); // hey
D.callStatic(); // hey
Другими словами, пока у вас есть неабстрактная версия A
, вы можете вызывать callStatic
(или любой статический метод/свойство) для этого типа, и он будет работать одинаково каждый раз!
Комментарии:
1. Хм, я что-то пропустил? Я попробовал ваше решение в typescript playground, и оно, похоже, не работает для меня, я получаю следующую ошибку
this.aType.prototype.callStatic is not a function
: typescriptlang.org/play? #код/… Я2. Извините, исправил и проверил мой ответ. Сейчас должно быть хорошо!
3. Ух ты! Спасибо! Я не знал, что мы можем создавать профсоюзы! Это работает на меня 🙂
4. @Solal Я сделал поправку. На самом деле они называются типами пересечений для
amp;
.|
это союз; моя вина. Все еще работает так же, хотя 🙂
Ответ №2:
Вы пытаетесь вызвать явный экземпляр A, в котором нет необходимости.
type AStatic<S extends A> = { new(): A };
abstract class A {
static callStatic<S extends AStatic<S>>(this: AStatic<S>) {
console.log('hey')
}
}
class B extends A {
}
class C {
aType: typeof A;
constructor(type: typeof A) {
this.aType = type;
B.callStatic()
}
}
const c = new C(B);
Поскольку метод callStatic является статическим, вы можете просто вызвать реализацию этого метода в B.
Комментарии:
1. Ну, если быть более конкретным, в моем случае у меня есть много классов, расширяющих A, и мне нужно иметь возможность вызывать статическую функцию для любого из них, а не только для B. Я обновил свой вопрос, чтобы лучше представить свое дело.