-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature request (separate proposal?): context.addPostInitializer()
#521
Comments
You can do that already with a class initializer that replaces the constructor function. |
Of course, I know I can work around it with a convoluted class decorator + getter decorator setup, but it is definitely not ideal. I don't want to have to do the following for this case: @classDeco
class Example {
#foo = 123
@deco
get foo() { return this.#foo }
}
function deco(_, context) {
context.addInitializer(function () {
// implement coordination with the class deco
})
}
function classDeco(Class) {
class SubClass extends Class {
constructor() {
// implement coordination with the getter deco
}
}
} I'm already familiar with this approach, this is how I avoid having to use A |
Babel's behavior is the ideal default. Having a getter and its decorator break due to a private field in the very same class is a bad experience. |
That seems like it'd allow you to easily write a class constructor that interacts with subclass constructors after they've run, which seems like a very bad idea - or are you just talking about a hook for a specific field that runs immediately after it's been initialized by the user? If so, can't you also already do that with a field decorator that wraps the initializer function's getter and setter? (that might not be on initialization, but it'd be on first use, at least) |
If you mean this, function getterDeco(_, context) {
context.addInitializer(function () {
doSomethingWith(this.constructor)
})
} that's already possible with Or did you mean something else?
Not sure what you mean. Got an example? I'm decorating a getter, not a field. |
(I reported the Babel bug, which I wish was not a bug but the default behavior) |
methods don't initialize tho, only fields do. |
I'm not sure what you're getting at, but getter decorators have |
The suggestion of using a class decorator @ljharb also means that user code in the user's A |
I’m not sure what you mean by “reliable”; can you elaborate on your use case? (either way any additive changes to decorators must happen in a separate proposal, regardless; this one’s stage 3) |
If a user uses a decorator, they might want to write code in their If the behavior of the class is defined in a decorator subclass instead of the user's class (instead of a member decorator's initializer), then the user's code in the user's own For example: @isReactive class MyClass {
@reactive foo = 123
constructor() {
createEffect(() => {
console.log(this.foo)
})
}
} In that example, But because the decorator's subclass constructor has not yet run in the user's @isReactive class MyClass {
@reactive foo = 123
constructor() {
createEffect(() => {
console.log(123) // no reactive variable is accessed here, just a plain value, therefore it cannot be reactive.
})
}
} Same problem with coordinating between a getter decorator and class decorator, only the decorator subclass will be able to set things up.
From a discussion could follow a proposal. Do I make one in a repo under my github username? |
Wouldn't this be fixed by #513 ? |
Decorators on instance things are available after a base class constructor, and after super in a derived class constructor. That’s pretty intentional and unlikely to change. |
@justinfagnani If that applies for getter/setter initializers, then yeah, otherwise no. But based on conversations, it seems like we really need more flexibility to choose before vs after. It depends on use case. A method decorator may want to addInitializer to run before class fields, so that fields can use the result. But a getter/setter decorator like in the above example would want to run after field initializers. We just need a more flexible API. But how? Seems like people want either before or after field decorators. And would it be better for all non-field initializers to run after fields by default? |
I don't think anyone proposed otherwise. The order of getter/setter vs field vs method vs accessor vs etc doesn't change the fact that they all run after super (or at top of constructor in a base class), and currently field accessors run after getter/setter initializers. |
Gotcha, thanks for clarifying. |
@rbuckton's "bucket" idea, is essentially asking for the same thing in a different way, if I'm not mistaken. The example in the OP throwing a runtime error seems totally bad. What's the reason we want it to be that way? |
private fields aren’t “names”; you can only access them syntactically. |
Non-field initializers added with
context.addInitializer()
run before field initializers according to the README, making it too easy to have problems with private fields. The README says:Example:
The error will be something like:
With TypeScript the error is thrown (correct, based on proposal-decorator's README):
TS playground
Babel does not throw, seems to run the initializer after class fields and the private field value is ready:
Babel repl
Feature Request
Assuming TypeScript and README are correct and Babel is wrong, it would be nice to have
context.addPostInitializer()
. It would work just like Babel'scontext.addInitializer()
currently does, but officially:If it is actually TypeScript and README that are incorrect and Babel is correct, then a converse
context.addPreInitializer()
API could be added. There probably are use cases for both.In my case, I want to use private fields, but I also want to grab getter initial values by reading them, and it's just too bad that private fields are getting in the way here. I don't want to regress back to
__private
naming convention.The text was updated successfully, but these errors were encountered: