如何在Babel + transform-decorators-legacy

时间:2016-09-01 09:30:17

标签: javascript decorator babel

在我的库中(对于AngularJS)我正在尝试实现以下功能:

  1. 您可以使用一些装饰器标记空类属性
  2. 在初始化过程中,此属性将替换为Object.defineProperty定义的getter。
  3. 用户可以在类中调用此属性,并调用getter。
  4. 但我在巴贝尔遇到了意想不到的行为。在库中使用的Typescript中,它运行良好,但是Babel创建了一些代码,这些代码将已经定义的属性重新定义为它的初始化器。

    这是ES2015中的装饰类:

    @Component({
      selector: 'test'
    })
    export class TestClass {
      @Inject('$http') $http;
      @Inject('$q') $q;
    }
    

    结果代码:

    var TestClass = exports.TestClass = (_dec9 = (0, _ngMetasys.Component)({
      selector: 'test'
    }), _dec10 = (0, _ngMetasys.Inject)('$http'), _dec11 = (0, _ngMetasys.Inject)('$q'), _dec9(_class4 = (_class5 = function TestClass() {
      (0, _classCallCheck3.default)(this, TestClass);
      // everything is OK, TestClass.prototype.$http is a getter with function () => $http.
    
      _initDefineProp(this, '$http', _descriptor5, this); // there are dragons. Property $http is redefined to undefined. 
    
      _initDefineProp(this, '$q', _descriptor6, this);
    }, (_descriptor5 = _applyDecoratedDescriptor(_class5.prototype, '$http', [_dec10], {
      enumerable: true,
      initializer: null
    }), _descriptor6 = _applyDecoratedDescriptor(_class5.prototype, '$q', [_dec11], {
      enumerable: true,
      initializer: null
    })), _class5)) || _class4);
    

    如何禁用此属性重新定义?有没有办法避免巴贝尔的财产重新定义或替代它?

1 个答案:

答案 0 :(得分:0)

我想我找到了问题的答案。 babel-plugin-transform-decorators-legacy中有一个测试允许设置属性描述符,甚至可以将简单属性转换为getter。

有一个限制。如果你想记住装饰者稍后改变它,它将无法工作。我没有正确调查它,但我认为我的问题是我在类(和属性)初始化后更改描述符的事实,并且我对描述符所做的更改不会影响已初始化的属性。

所以有测试给了我提示。它来自here

it('should support mutating an initialzer into an accessor', function(){
  function dec(target, name, descriptor){
    expect(target).to.be.ok;
    expect(name).to.eql("prop");
    expect(descriptor).to.be.an('object');

    let {initializer} = descriptor;
    delete descriptor.initializer;
    delete descriptor.writable;

    let value;
    descriptor.get = function(){
      if (initializer){
        value = '__' + initializer.call(this) + '__';
        initializer = null;
      }
      return value;
    };
  }

  class Example {
    @dec
    prop = 3;
  }

  let inst = new Example();

  expect(inst.prop).to.eql('__3__');
});