Skip to content
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

Suggestion: Provide additional context about the class to member decorators #466

Open
rbuckton opened this issue Apr 12, 2022 · 4 comments

Comments

@rbuckton
Copy link
Collaborator

rbuckton commented Apr 12, 2022

Member decorators (method, accessor, field, etc.) in the current proposal do not have access to the class constructor or prototype, and thus have no access to the name of the class containing the decorated element. This would be valuable information for something like a @logged decorator.

I would propose the addition of either a className property to the context, or something like the class property below:

type Decorator = (value: Input, context: {
  kind: string;
  name: string | symbol;
  access: {
    get?(): unknown;
    set?(value: unknown): void;
  };
  private?: boolean;
  static?: boolean;
  addInitializer?(initializer: () => void): void;

  parent?: {
    kind: "class";
    name: string | undefined;

    // other future class-specific context information such as:
    
    // add a static initializer to the class, even for instance members:
    addInitializer(initializer: () => void): void;
     
    // attach class-specific metadata (separately from function-specific metadata)
    metadata: Record<string | symbol, unknown>;
  };
}) => Output | void;

Related: #465

@ArsenyYankovsky
Copy link

ArsenyYankovsky commented Sep 9, 2023

I want to highlight that is a blocker for a lot of use cases, including several existing popular ORMs (MikroORM, TypeORM etc.).

@Haixing-Hu
Copy link

@rbuckton Actually, we can retrieve the class name from the decorated method. Here's a demonstration:

function Log(target, context) {
  return function (...args) {
    const prototype = Object.getPrototypeOf(this);
    const Class = prototype.constructor;
    const className = Class.name;
    console.debug(`${className}.${context.name}:`, ...args);
    return target.apply(this, args);
  }
}

class Test {
  @Log
  add(x, y) {
    return x + y;
  }
}

describe('Test @Log decorator for class methods', () => {
  test('should work', () => {
    const t = new Test();
    t.add(1, 2);
  });
});

@ArsenyYankovsky
Copy link

@Haixing-Hu What about the field decorators? Many ORMs (and some validation libraries) collect and save metadata using decorators on class fields and they need access to the class and field names.

@rbuckton
Copy link
Collaborator Author

@rbuckton Actually, we can retrieve the class name from the decorated method. Here's a demonstration: [...]

That would give you the class name of the instance constructor, not the class name of the class it was declared on, and requires method invocation to access. You could use context.addInitializer, but you that still require an instance be created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants