-
Notifications
You must be signed in to change notification settings - Fork 116
Description
In https://github.com/tc39/proposal-decorators#class-auto-accessors it is not clear what context.access does. Is this to access the underlying unnamed private field that the accessor wraps, or is it a way to invoke the outermost decorated getter/setter for something like @dec accessor #x;?
This becomes even more complicated when combined with the Grouped and Auto-accessors proposal, as its possible for an auto-accessor to have multiple private elements as well: the unnamed private backing field and a private-named setter:
class C {
@dec2
@dec1
accessor x { get; #set; }
@dec2
@dec1
accessor #y { get; set; }
}If context.access gives you access to the unnamed backing field, then there is a disparity between what you can do with the getter and setter:
- If you want to invoke the underlying getter, you can use
get.call(this). - If you want to get the value from the instance by name, you can pipe through all decorator replacements using
this[context.name]. - If you want to invoke the underlying setter, you can use
set.call(this, value). - However, there is no way to set the value on the instance by its private name to pipe through all decorator replacements.
Giving access to the unnamed backing field seems to align with context.access in Class Field Decorators.
However, If context.access gives you the ability to evaluate the outermost decorated getter/setter, then there is no way for a decorator to read the unnamed backing field (which would be useful for serializers/deserializers).
Giving access to the outermost decorated getter/setter seems to align with context.access in Class Accessor Decorator.
Hence my confusion. It might be better to distinguish between direct access (as with private fields) and indirect access (for interacting with the outermost decorated declaration):
type Decorator = (value: Input, context: {
kind: string;
name: string | symbol;
directAccess?: { // access private field directly
get(target: object, receiver: object): unknown; // uncurry `this` and pass in `receiver` to match Reflect.get
set(target: object, value: unknown, receiver: object): void; // uncurry `this` and pass in `receiver` to match Reflect.set
};
indirectAccess?: { // access member via outermost result
get?(target: object, receiver: object): unknown; // uncurry `this` and pass in `receiver` to match Reflect.get
set?(target: object, value: unknown, receiver: object): void; // uncurry `this` and pass in `receiver` to match Reflect.set
};
isPrivate?: boolean;
isStatic?: boolean;
addInitializer?(initializer: () => void): void;
getMetadata(key: symbol);
setMetadata(key: symbol, value: unknown);
}) => Output | void;NOTE: I chose the names directAccess and indirectAccess as a starting point. I'm more than happy discussing alternatives or an alternative API design that serves the same needs.
Finally, is there a reason to distinguish between auto-accesssors and possible future grouped-accessors using the kind of "auto-accessor"? For grouped-accessors will you just use "accessor", or could you use "accessor" for both and distinguish between each based on the presence of context.access (nee. context.directAccess, etc).