-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Support for auto-accessor fields from the Stage 3 Decorators proposal #49705
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
Conversation
@typescript-bot perf test |
b3487dc
to
a37f09a
Compare
@typescript-bot perf test |
Heya @rbuckton, I've started to run the perf test suite on this PR at a37f09a. You can monitor the build here. Update: The results are in! |
a37f09a
to
54024cf
Compare
@rbuckton Here they are:Comparison Report - main..49705
System
Hosts
Scenarios
Developer Information: |
@typescript-bot run dt |
Heya @rbuckton, I've started to run the diff-based user code test suite on this PR at 54024cf. You can monitor the build here. Update: The results are in! |
@rbuckton |
Why is this a thing? Like, what problem does it actually solve (genuine question, not snark)? The generated accessors don't do anything and unlike, e.g., C#, changing a plain property to an accessor isn't generally an API break... edit: Oh, I see, it's mostly because decorators will apparently make a distinction between field and accessor. |
This was a requirement from VM implementers to avoid the potential hidden shape changes that could occur if you were able to convert a field declaration into an accessor dynamically rather than statically. It also helps to avoid issues with public field shadowing in cases like the following, such as with class C {
// observe attaches an accessor pair to C.prototype, but the field `x` is defined
// on the instance, shadowing the accessor pair.
@observe x = 1;
}
// vs
class C {
// observe can now instead intercept the `{ get, set }` provided to attach its behavior.
@observe accessor x = 1;
} |
9a9624b
to
ba6e369
Compare
What are the assignability rules for auto-accessor fields? I guess that they're the same as a normal class field, but might be missing something. |
They should be treated the same as we would a get/set pair. |
Ah, that explains why the code in the checker is with the existing accessor code, not the property declaration code. |
Very naive question: EDIT: I guess the keyword for readonly properties would be
into
But that would be a very breaking change; which could be enabled by a |
More generally, is there a reason that |
It's not currently supported because the accessor isn't actually read-only (a setter is still generated) and that might break user expectations. Also, support for actual read-only accessors is planned as part of https://github.com/tc39/proposal-grouped-and-auto-accessors, which is blocked on any advancement until after Decorators reaches Stage 4. With the full auto-accessors proposal, you could accomplish a true read-only accessor using the following syntax: class C {
accessor x { get; } = 1;
} Which would transform into something like this: class C {
#x_accessor_storage = 1;
get x() { return this.#x_accessor_storage; }
} |
Actually having a |
This PR adds support for
accessor
field declarations described in the Stage 3 Decorators proposal.An Auto-Accessor is a field declaration that will be transformed by the runtime into a pair of
get
andset
accessors that access a private backing field:When you use
--target ESNext
,accessor
fields will be left as is to be transformed by the runtime. Any earlier--target
will result in TypeScript downleveling theaccessor
field to a compatible runtime implementation.Auto-Accessor fields have several capabilities:
get
/set
without a superclass field potentially shadowing the property during initialization.get
andset
accessor pair and can replace them without changing the runtime shape of the class.In addition, there are several rules around the use of the
accessor
keyword:accessor
fields require a minimum of--target ES2015
, similar to our support for private identifiers (i.e.,#x
) and for the same reasons (a dependency onWeakMap
/WeakSet
).accessor
may only appear in front of field declarations on aclass
. It is not supported ininterface
or object type literals.accessor
cannot be used withreadonly
ordeclare
on the same field declaration.accessor
can be used in an ambient class declaration.accessor
field declarations can be decorated with TypeScript's legacy decorators (i.e., under--experimentalDecorators
). They will behave as if you decorated aget
orset
declaration (i.e., you will receive aPropertyDescriptor
at runtime with bothget
andset
functions).accessor
will also be marked withaccessor
in the output declaration file.accessor
field does not make a class nominal, despite the synthetic private backing field.Symbol
for anaccessor
field is not aSymbolFlags.Property
, but rather aSymbolFlags.GetAccessor | SymbolFlags.SetAccessor
.NOTE: This is not an implementation of the full Stage 3 Decorators proposal as that effort is still in progress.