Actually, I think it is almost possible. After doing a quick glance over the decorator proposal, I see they're providing a new "accessor" property type, that auto-defines a getter and setter on the class, and can be decorated.
So, you could have a decorator such as this:
class MyClass {
@externallyReadOnly accessor myData = 2
}
And have the decorator desurgar that to this:
class MyClass {
get myData() {
return ...
}
set myData(newVal) {
if (!new.self) throw new Error('Can not read this property from outside')
... = newVal
}
}
The ...
would be replaced with accessing/setting metadata stuff, that I see decorators support. The decorator would be able to properly default-initialize to the correct value. (In the above example, it would be default-initialized to 2).
The only missing piece is "new.self" that @Jonas_Wilms proposed here in order to enable private constructors. The idea of "new.self" is that it'll simply return true if you're being called from within a class definition, and false otherwise. I don't think this exact idea would be useable here, as the actual getter/setter definitions are created from outside the class, by the decorator, so new.self wouldn't be able to target the class, but perhaps we could find a solution that could work for both use cases.
I'd rather we find a way to empower decorators to support this kind of feature (and perhaps provide built-in convenient decorators if wanted), then add new syntax to achieve this.
Edit: But the get state = #state
syntax shorthand looks pretty cool too,. Or, even better, if you could just define getters as arrow functions, so they weren't so verbose, e.g. get state = () => this.#state