Typescript: Вызов статической функции с параметром «this».

#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 и D

2. Я беру свои слова обратно. Я вижу, что вы 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. Я обновил свой вопрос, чтобы лучше представить свое дело.