Абстрактный метод не вызывается в конструкторе

У меня есть базовый класс, который является абстрактным, и следующее определение опоры и конструктор:

protected abstract connectToFirebase: (config: any) => Promise<void>;
protected abstract listenForConnectionStatus: () => void;

constructor(config: IFirebaseConfig = {}) {
  if (config.mocking) {
    this._mocking = true;
    this.getFireMock();
  } else {
    this._mocking = false;
    this.connectToFirebase(config).then(() => this.listenForConnectionStatus());
  }
}

Я хочу, чтобы конкретные подклассы определяли connectToFirebase() и listenForConnectionStatus(), но, к сожалению, я делаю здесь что-то не так, поскольку получаю следующую ошибку:

Абстрактный метод не вызывается в конструкторе

Я все еще немного грубо разбираюсь в деталях синтаксиса класса JS, поэтому я не совсем уверен, относится ли это к TS или JS. Кто-нибудь может помочь?

Если вы объявите его как абстрактный метод, он будет вызываемым. Но производные классы не могут установить абстрактное свойство перед вызовом базового конструктора - через super. Это проблема.

cartant 10.06.2018 09:38

да, когда я уже собирался лечь спать, я понял ... спасибо за вашу помощь

ken 10.06.2018 09:39

Связанный: github.com/Microsoft/TypeScript/issues/…

JLRishe 10.06.2018 09:39

Я совершенно уверен, что это TS, потому что Javascript довольно гибкий, и похоже, что это ошибка, которая уже происходит в редакторе, верно !?

Nikolaus 10.06.2018 12:38
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
129
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно объявить его как абстрактный метод, а не как абстрактное свойство:

protected abstract connectToFirebase(config: any): Promise<void>;
protected abstract listenForConnectionStatus: () => void;

constructor(config: IFirebaseConfig = {}) {
    this.connectToFirebase(config).then(() => this.listenForConnectionStatus());
}

Причина, по которой вы можете объявить listenForConnectionStatus как абстрактное свойство, заключается в том, что он вызывается внутри стрелочной функции. Вы получите сообщение об ошибке, если попытаетесь сделать это:

// Abstract property 'listenForConnectionStatus' in class 'Foo' cannot be accessed in the constructor.
this.connectToFirebase(config).then(this.listenForConnectionStatus);

Причина, по которой между ними есть разница, заключается в том, как они создаются.

При объявлении как свойства ваш класс, расширяющий базовый класс, будет выглядеть следующим образом:

var Concrete = /** @class */ (function (_super) {
    __extends(Concrete, _super);
    function Concrete() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.connectToFirebase = function (config) { return null; };
        return _this;
    }
    return Concrete;
}(Base));

Как видите, он вызывает super, а тогда устанавливает _this.connectToFirebase, поэтому при вызове superthis.connectToFirebase будет undefined.

Сравните это со скомпилированным JavaScript для абстрактного метод:

var Concrete = /** @class */ (function (_super) {
    __extends(Concrete, _super);
    function Concrete() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Concrete.prototype.connectToFirebase = function (config) {
        return null;
    };
    return Concrete;
}(Base));

connectToFirebase объявляется на prototype одновременно с объявлением конструктора. Это означает, что при фактическом вызове конструктора он вызывает super, но connectToFirebase уже определен и доступен для использования.

Другие вопросы по теме