Получить доступ к статическим свойствам класса с помощью BabelJS 6

Ниже приведено минимальное приложение, демонстрирующее проблему:

'use strict';

var _ = require('underscore');

class Model
{
    constructor(value) {
        this._value = value;
    }

    get value() {
        return this._value;
    }

    toJS() {
        return this.value;
    }
}

class ObjectModel extends Model
{
    static properties = {};

    constructor(value) {
        super(_.extend({}, new.target.properties, _.pick(value, _.keys(new.target.properties))));
    }
}

class PostModel extends ObjectModel
{
    static properties = {
        title: 'Hello'
        /* content: '<p>Lorem ipsum dolor sit amet</p>' */
    };
}

console.log(new PostModel({title: 'Nice day', aa: 11, bb: 22}).toJS());

Должно производить {title: 'Nice day'}, Вместо этого он даже не компилируется. Я получаю это:

$ babel app.js
SyntaxError: app.js: 'this' is not allowed before super()

Я понимаю, почему это было сделано для свойств объекта. Но я не могу понять, почему это также было сделано для переменных класса.

В BabelJS 5 я использовал этот трюк, который сделал эту работу:

class ObjectModel extends Model
{
    static properties = {};

    constructor(value) {
        if (0) { super(); }
        super(_.extend({}, this.constructor.properties, _.pick(value, _.keys(this.constructor.properties))));
    }
}

В версии 6 он компилируется, но при запуске выдает ошибку:

Uncaught TypeError: Cannot read property 'constructor' of undefined

Есть ли способ получить доступ к классу статических переменных перед вызовом super? Используя что-то вроде init() вместо constructor это не вариант. Может быть, создать собственный плагин преобразования?

Детали системы:

$ babel --version
6.2.0 (babel-core 6.2.1)

$ cat .babelrc
{
    "presets": ["es2015", "stage-1"]
}

$ babel-doctor

Babel Doctor
Running sanity checks on your system. This may take a few minutes...

✔ Found config at /path/to/.babelrc
✔ No duplicate babel packages found
✔ All babel packages appear to be up to date
✔ You're on npm >=3.3.0

Everything looks all right!

1 ответ

Решение было следующим:

  1. Придерживайтесь new.target как предложено @sjrd и @loganfsmyth:

    class ObjectModel extends Model
    {
        static properties = {};
    
        constructor(value) {
            super(_.extend({}, new.target.properties, _.pick(value, _.keys(new.target.properties))));
        }
    }
    
  2. Создать транспортер, который преобразует все new.target (ES6) в this.constructor (ES5):

    function transpileNewTarget()
    {
        return {
            visitor: {
                MetaProperty(path) {
                    if (path.isMetaProperty() && path.node.meta.name == 'new' && path.node.property.name == 'target') {
                        path.replaceWithSourceString('this.constructor');
                    }
                }
            }
        };
    }
    
Другие вопросы по тегам