I think the next (simplified) code should be working:
class WfConfigurable {
constructor(config) {
this._init(config);
}
_init(config) {
this.configure(config);
}
configure(config) {}
}
class WfStateful extends WfConfigurable {
#saveSuspend = 0;
constructor(config) {
super(config);
}
get saving() { return this.#saveSuspend == 0; }
configure(config) {
this.suspendSave();
super.configure(config);
this.continueSave();
}
suspendSave() {
this.#saveSuspend++;
}
continueSave(force) {
if (force) {
this.#saveSuspend = 0;
} else {
this.#saveSuspend = Math.max(this.#saveSuspend - 1, 0);
}
}
}
class WfApp extends WfStateful {
constructor(config) {
super(config);
}
}
const wfApp = new WfApp({});
But I have got the next error message:
TypeError: Cannot read private member #saveSuspend from an object whose class did not declare it
at WfApp.suspendSave ((index):24:13)
at WfApp.configure ((index):19:14)
at WfApp._init ((index):7:14)
at new WfConfigurable ((index):4:14)
at new WfStateful ((index):15:9)
at new WfApp ((index):37:9)
at (index):41:15
For example, this works well:
class A {
#priv = 'hello';
constructor() {
console.log('A');
}
get priv() {
return this.#priv;
}
set priv(p) {
this.#priv = p;
}
}
class B extends A {}
const b = new B();
b.priv += ' babe';
console.log(b.priv);
Writes out: "hello babe"
The error message "Cannot read private member #saveSuspend
from an object whose class did not declare it" is slightly confusing. More accurate in this case would be "from an object where it is not (yet) initialised".
Private fields, and fields in general, are created on the instance (and initialised with the value defined in the class body) when the super()
constructor returns. If that constructor is calling an overridden method (configure
) before the initialisation is done, it will not be able to access the non-existing field. With private fields, it just throws an exception because the field doesn't exist, instead of returning undefined
like a normal property.
The only solution is to never call an overrideable method from a constructor. This is true in any language. In your case, just get rid of the configure
method altogether, it does not thing.