Автоматически добавлять класс в список через декоратор классов? - PullRequest
0 голосов
/ 25 января 2019

Можно ли получить дескриптор "объекта класса" (конструктора) в декораторе?

Справочная информация: я хочу проанализировать формат json'ish со строковыми значениями, которые помечены с типами, например"@date:2019-01-25" или "@latlong:51.507351,-0127758".

Это попытка модернизации старой библиотеки js, в которой это было достигнуто путем переопределения как создания подклассов, так и создания экземпляров.

Декораторы выглядели многообещающе, по крайней мере, я могуопределить тег как атрибут класса:

function dkdatatype({tag}) {
    return function decorator(cls) {
        if (cls.kind !== 'class') throw `not class ${cls.kind}`;

        cls.elements.push({
            kind: 'field',
            key: 'tag',
            placement: 'static', 
            descriptor: {
                configurable: false,
                enumerable: true,
                writable: false
            },
            initializer: () => tag
        });

        return {
            kind: 'class',
            elements: cls.elements
        };
    };
}

@dkdatatype({tag: '@date:'})
export class DkDate extends datatype {
    constructor(...args) {
        super();
        const clstag = this.constructor.tag;
        if (typeof args[0] === 'string' && args[0].startsWith(clstag)) {
            this.value = new Date(args[0].substr(clstag.length));
        } else {
            this.value = new Date(...args);
        }
    }
    toJSON() {
        return this.constructor.tag + this.value.toISOString().slice(0, 10);
    }
}

Я могу добавить класс в реестр типов вручную:

type_registry[DkDate.tag] = DkDate

, но есть ли способ сделать это автоматически (и только один раз) от декоратора (или, может быть, базового класса, или как-то иначе)?

1 Ответ

0 голосов
/ 26 января 2019

Согласно текущей документации , вы хотите добавить свойство extras в дескриптор класса, возвращаемый вашим декоратором, который должен содержать дескриптор "hook", и этот дескриптор должен иметь finish метод, который будет вызываться с самим классом в качестве аргумента после полного определения класса.

Вот пример кода:

function defineElement(tagName) {
  return function(classDescriptor) {
    let { kind, elements } = classDescriptor;
    assert(kind == "class");
    return {
      kind,
      elements,

      // This callback is called once the class is otherwise fully defined
      extras: [
        {
          kind: "hook",
          placement: "static",
          finish(klass) {
            window.customElements.define(tagName, klass);
          }
        }
      ]
    };
  };

В вашем случае extras будет выглядеть так:

extras: [
  {
    kind: "hook",
    placement: "static",
    finish(klass) {
      type_registry[tag] = klass;
    },
  },
],
...