Получить экземпляр класса свойства в декораторе свойства - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь написать @Prop декоратор, чтобы помочь мне установить пользовательские атрибуты элементов.

Вот код, который я пытаюсь достичь:

class MyClass extends HtmlElement {
   get text() {
     return this.getAttribute('text')
   }

   set text(newVal){
     this.setAttribute('text', newVal)
   }

   connectedCallback() {
     this.innerHTML = `<div>${this.text}</div>`
   }
}

Этокласс с декоратором

class MyClass extends HtmlElement {
   @Prop() text: string;

   connectedCallback() {
     this.innerHTML = `<div>${this.text}</div>`
   }
}

Это функция декоратора

const Prop = () => (target : any, key : string) => {
    const getter = () => target.getAttribute(key);
    const setter = (newVal) => target.setAttribute(key, newVal);

    if (!delete this[key]) return;
    Object.defineProperty(target, key, {
        get: getter,
        set: setter
    });
}

Однако всякий раз, когда вызывается функция геттера, я получаю эту ошибку:

Uncaught TypeError: Illegal invocation
    at HTMLElement.getter (app.js:16)

Проверкаapp.js:16 показывает эту строку кода:

const getter = () => target.getAttribute(key);

с target.getAttribute(key);, подчеркнутым.

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Декораторы вызываются классом как целью, а не экземпляром класса.Экземпляр класса появится в функции getter / setter как this.Вот почему использование функции со стрелкой является плохой идеей, поскольку они захватывают this с сайта объявления.Использование обычной функции работает лучше всего в этом случае.

const Prop = () => (target: any, key: string, descriptor: PropertyDescriptor) => {
    const getter = function (this: HTMLElement) {
        return this.getAttribute(key);
    }
    const setter = function (this: HTMLElement, newVal) {
        this.setAttribute(key, newVal);
    }
    descriptor = descriptor || {};
    descriptor.get = getter;
    descriptor.set = setter;
    return descriptor;
}

class MyClass extends HTMLElement {
    @Prop() text: string;

    connectedCallback() {
        this.innerHTML = `<div>${this.text}</div>`
    }
}
0 голосов
/ 27 августа 2018

Чтобы определить методы получения и установки, просто удалите свойство, а затем добавьте его заново, но используйте дескриптор свойства

const Prop = () => (target : any, key : string, descriptor: PropertyDescriptor) => {
  // Could be inlined...
  const getter = () => target.getAttribute(key);
  const setter = (newVal) => target.setAttribute(key, newVal);

  descriptor.set = setter
  descriptor.get = getter
}

https://www.typescriptlang.org/docs/handbook/decorators.html

...