Tamas
Tamas

Reputation: 11214

How do I use JavaScript decorators on a class instance via Babel?

Given the following .babelrc config:

{
  "plugins": [
    ["@babel/plugin-proposal-decorators", {
      "legacy": false,
      "decoratorsBeforeExport": false
    }]
  ]
}

I can't get the class decorators to work:

@annotation
class MyClass { }

function annotation(target) {
   target.annotated = true;
}

const c = new MyClass();
console.log(c);

Also, console.log(target) yields the following:

Object [Descriptor] { kind: 'class', elements: [] }

For the console.log(c) statement I'd expect to see the annotated property added, however what I get is just MyClass {}.

Some additional clarification - I know of the legacy: true flag but I wish to use the spec as it is now, without the legacy fallback. I did some additional research and I think I'm on the right path here, here's the updated code:

@annotation
class MyClass { }

function annotation(descriptor) {
  const {
    kind,
    elements
  } = descriptor;

  const newElements = elements.concat([{
    kind: 'field',
    placement: 'own',
    descriptor: {
      annotated: true
    }
  }]);
  return {
    kind,
    elements: newElements
  }
}

const c = new MyClass();
console.log(c);

The above still doesn't work but at least I am no longer getting weird errors :)

Please read the comments on the accepted answer to see some potential solutions to this, if interested.

** UPDATE ** I actually managed to figure it out - using the legacy: false option:

@annotation
class MyClass { }

function annotation(descriptor) {
  const {
    kind,
    elements
  } = descriptor;

  const newElements = elements.concat([{
    kind: 'field',
    placement: 'own',
    key: 'annotated',
    initializer: () => true,
    descriptor: {
      configurable: true,
      writable: true,
      enumerable: true
    }
  }]);
  return {
    kind,
    elements: newElements
  }
}

const c = new MyClass();
console.log(c); // MyClass { annotated: true }

Upvotes: 2

Views: 743

Answers (1)

jhpratt
jhpratt

Reputation: 7130

Return a new class that sets the property in the constructor.

@annotation
class MyClass { }

function annotation(target) {
  return class extends target {
    constructor(...args) {
      super(...args);
      this.annotated = true;
    }
  }
}

const c = new MyClass();
console.log(c);

Upvotes: 1

Related Questions