Skip to content

Design Meeting Notes, 10/21/2022 #51322

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

Closed
DanielRosenwasser opened this issue Oct 27, 2022 · 0 comments
Closed

Design Meeting Notes, 10/21/2022 #51322

DanielRosenwasser opened this issue Oct 27, 2022 · 0 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Oct 27, 2022

Decorators!

#50820

https://2ality.com/2022/10/javascript-decorators.html

  • Metaprogramming feature that allows one to modify classes and class members.

  • Inspired a bit by Python decorators.

  • Started work on these in 2015, changed quite a bit since then.

  • log example - allows one to replace a method with one that always prints out the method name upon its invocation/return.

  • Useful for

    • Metadata
      • e.g. wrapping methods, validating inputs/outputs, marshalling data (protobufs, wasm interop, ...), auto-binding a method to its target object, ...
    • Registration
      • ORMs, dependency injection, RTTI, unit testing, routing, debugging.
  • So whats a decorator look like today?

    declare function decorator<T>(target: T, context: DecoratorContext): T | void;
  • They can decorate 6 things on a class

    • the class itself
    • properties
    • accessor members
    • methods
    • get accessors
    • set accessors
  • When a decorator is called, the context tells you what kind of member was decorated via a kind property.

  • Class decorators

    • Context doesn't give you much - just the ability to run something after all statics and decorators have evaluated.
      • Does addInitializer apply to the original (decorated) class, or whatever gets replaced?
        • The replacement.
        • But the type expects the input type.
        • Just today. Today we expect the types to be the same.
      • Aside - everyone seems unhappy that addInitializer passes in the target via this instead of an argument.
        • It mirrors static blocks. The mental model is you should think of a class decorator's addInitializer as a new static block.
    • Otherwise, you can just replace the class entirely
      • Even with a function or a Proxy, though those are involved to get working.
  • Type mutation?

    • Not in the first pass of this proposal.
  • Method decorators

    • Context also provides info about if the member was private or static.
    • Also has an access member to get the original member.
      • NOT actually the case.
      • Provides you a way of accessing the member on the corresponding target (static -> class, non-static -> instance) as if you had written it in a respective static/non-static method.
  • get accessor and set accessor decorators

    • Decorating a specific decorator method, not the functional name.
    • Today TypeScript only allows you to decorate one. Current proposal means we have to allow each to be decorated independently.
    • The access property allows you to get the property, or set the property. Not the method itself.
    • If you want to decorate both with shared state?
      • Have to create an object with a respective get/set decorator.
      • Let's come back to this.
  • Class fields

    • Original proposal was just about knowing whether a field exists - but people used Object.defineProperty and then the finalized class fields semantics (enabled in --useDefineForClassFields) botched this.
      • But new decorators proposal remedies this.
    • These field decorators are allowed to return a function that receives the value of a field initializer, and these functions can return a derived value.
    • Can these be used to enable @lazy?
      • No, you need accessor decorators for those.
    • addInitializer runs before all actual initializers upon construction of the target.
  • Accessor decorators

    • New class member type.

      class C {
        accessor x = 0;
      }
      
      // sugar for
      
      class C {
        // Imagine `#x` is really unique,
        // and otherwise not witnessable
        #x = 0;
        get x() { return this.#x; }
        set x(value) { this.#x = value; }
      }
    • Allows cutting down between defining both accessors, and a field if you need to initialize.

    • For decorators, allows one to decorate both.

    • access has both a get and set.

  • Some niceties of the current proposal - decorators can declare more-specific types for what they can be passed.

    • e.g. a decorator can say "I only can take contexts that can be methods that are static and private."
    • Error messages are bad, but we can revisit how that works.
  • TypeScript-related work?

    • declare field decorators
    • Type mutations via decorators
    • --emitDecoratorMetadata?
    • Design-time decorators?
    • Type decorators?
  • If you want nightmares, look at the __esDecorate helper.

@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Oct 27, 2022
@DanielRosenwasser DanielRosenwasser changed the title Design Meeting Notes, 10/26/2022 Design Meeting Notes, 10/21/2022 Oct 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

2 participants