Короче говоря
Как объявить в TypeScript: В этом классе любое свойство, начинающееся с '$', является ссылкой на элемент?
Контекст
I have a Custom Element class method that automatically stores any child element having attribute data-reference
in a property named after its value prefixed by '$'.
It works perfectly in vanilla JavaScript :
class SomeComponent extends HTMLElement {
connectedCallback() {
this.setReferences()
console.log(this.$myRef) // <div data-reference="myRef"></div>
}
setReferences() {
const referencedElements = this.querySelectorAll('[data-reference]')
referencedElements.forEach((element) => {
const referenceName = '$' + element.getAttribute('data-reference')
this[referenceName] = element
})
}
}
customElements.define('some-component', SomeComponent)
<some-component>
<div data-reference="myRef"></div>
</some-component>
Но это не скомпилируется в TypeScript, кто не знает о свойстве $myRef
:
console.log(this.$myRef) // Property '$myRef' does not exist on type 'SomeComponent'
^^^^^^
Пока я придумал 3 обходных пути, но ни один из них не полностью удовлетворяет.
1. Утверждение типа
Неа!
console.log((this as any).$myRef) // <div data-reference="myRef"></div>
Дело в том, чтобы обеспечить быстрый доступ к любому $ref
, поэтому добавление as any
или <any>
(плюс скобки) не является жизнеспособным решением.
2. Литерал объекта
Вероятно, самый чистый, но не совсем то, чего я хочу достичь.
type ElementReferenceMap = { [key: string]: Element }
class SomeComponent extends HTMLElement {
ref: ElementReferenceMap = {};
setReferences() {
const referencedElements = this.querySelectorAll('[data-reference]');
referencedElements.forEach((element) => {
const referenceName = element.getAttribute('data-reference');
this.ref[referenceName] = element as Element;
})
console.log(this.ref.myRef); // <div data-reference="myRef"></div>
}
}
Переименовав его в this.$.myRef
, я стал ближе, но он все еще не эквивалентен стандартной версии JavaScript.
3. Свойство индекса
Работает, как и ожидалось (как и версия JavaScript), но кажется неправильным, так как допускает любое значение свойства.
class SomeComponent extends HTMLElement {
// [x: string]: Element; // conflict with other properties
[x: string]: any; // ok
setReferences() {
const referencedElements = this.querySelectorAll('[data-reference]');
referencedElements.forEach((element) => {
const referenceName = '$' + element.getAttribute('data-reference');
this[referenceName] = element;
})
console.log(this.$myRef); // <div data-reference="myRef"></div>
}
}
Возможно, мне не хватает очевидного решения, так как я новичок в TypeScript. Заранее спасибо!