tc39/proposal-decorators

auto-accessor: addInitializer() or {initialize}

Closed this issue · 4 comments

The current README say:

Auto-accessors can be decorated, and auto-accessor decorators have the following signature:

type ClassAutoAccessorDecorator = (
  value: {
    get: () => unknown;
    set(value: unknown) => void;
  },
  context: {
    kind: "auto-accessor";
    name?: string | symbol;
    access: { get(): unknown, set(value: unknown): void };
    isStatic: boolean;
    isPrivate: boolean;
    addInitializer?(initializer: () => void): void;
    defineMetadata(key: string | symbol | number, value: unknown);
  }
) => {
  get?: () => unknown;
  set?: (value: unknown) => void;
  initialize?: (initialValue: unknown) => unknown;
} | void;

As you can see, it's included addInitializer() and the return { initialize(){} }. It's redundant.

I prefer to use addInitializer() like the other decorators, but in the text it only mentions the initialize return together with the get and set methods.

initialize is different than addInitializer. initialize is pipelined with the accessor's original initializer, receiving the value from the previous initializer, and it can replace the value. Initializers added via addInitializer run after the field has been defined, and they do not receive the original value. They can do other things though, such as use defineProperty to redefine the field. Essentially, they are different use cases.

addInitializer may be better named as addFinisher or something else to distinguish it from field/accessor initializers. This would make the @init: syntax make even less sense though. It could be changed to @finish: or something like that, possibly.

Thanks @pzuraq It's a very important difference. Perhaps the addFinisher is a good option for avoid confusions as me.

Other question about the same issue. Before this change the fields decorator cannot call with @init:. Is it true?

Yes, before this change the idea was that they would be mutually exclusive. Now they're two separate features with different use cases, so you can use @init: with any decorator to add an additional finisher-initializer.