У меня есть базовый класс, который является абстрактным, и следующее определение опоры и конструктор:
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. Кто-нибудь может помочь?
да, когда я уже собирался лечь спать, я понял ... спасибо за вашу помощь
Связанный: github.com/Microsoft/TypeScript/issues/…
Я совершенно уверен, что это TS, потому что Javascript довольно гибкий, и похоже, что это ошибка, которая уже происходит в редакторе, верно !?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам нужно объявить его как абстрактный метод, а не как абстрактное свойство:
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 уже определен и доступен для использования.
Если вы объявите его как абстрактный метод, он будет вызываемым. Но производные классы не могут установить абстрактное свойство перед вызовом базового конструктора - через
super. Это проблема.