我有一个基类
abstract
,扩展 HTMLElement
,它调用 CustomElementRegistry.define
。 Typescript 不喜欢使用 this
作为第二个参数,因为基类是 abstract
。但这似乎是不正确的,因为显然最终类永远不可能是抽象的。我必须使用下面丑陋的演员阵容。有更好的方法吗?
abstract class CustomElement extends HTMLElement {
constructor() {
super();
}
// Without a cast, the `this` argument gets this error:
// tsbug.ts:12:6 - error TS2345: Argument of type 'this' is not assignable to parameter of type 'CustomElementConstructor'.
// Type 'CustomElement' is not assignable to type 'CustomElementConstructor'.
// Type 'CustomElement' provides no match for the signature 'new (...params: any[]): HTMLElement'.
register() {
customElements.define(
"custom-element",
this, // This argument gets the error.
// If you replace the above `this` argument with the one below, it works.
// this as unknown as new () => HTMLElement,
{});
}
}
class MyElement extends CustomElement {
constructor() {
super();
this.register();
}
}
const e = new MyElement();
您尝试做的事情是不正确的。
CustomElement
的实例不应该尝试使用自定义元素注册本身。该逻辑比类内部的逻辑更高。
考虑一下如果你写的话会发生什么
const a = new MyElement();
const b = new MyElement();
这两个都会尝试注册,并使用自定义元素注册表重新注册自己。此外,每次您尝试在标记中使用自定义元素时都会发生这种情况。这不好。
相反,您的代码应该对更接近的设置进行建模:
customElements.define("custom-element", MyElement, {});
const a = new MyElement();
const b = new MyElement();
抛开设计问题不谈,您正在寻找的东西在正确的 OO 范式中是不可能实现的。
类不会获得可动态访问的对其自身的静态引用。 TypeScript 正确标记了一个问题:
customElements.define(
"custom-element",
this,
// This is a reference to an *instance* of a class, not to a constructor.
/// Casting will not make it work. You need a reference to the class you want to register.
{});
customElements.define
的第二个参数必须是CustomElementConstructor
的实例,它在“lib.dom.d.ts”中定义如下:
interface CustomElementConstructor {
new(...params: any[]): HTMLElement;
}
因此,您的代码错误,因为您传递的是 HTMLElement(子类)的 instance,而不是传递 constructor 作为第二个参数。
也就是说,这只是不是定义自定义 HTML 元素的正确方法。如果您询问(在评论中),我可以对此进行扩展,无论如何,作为初学者,这里是相关文档的链接:https://developer.mozilla.org/en-US/docs/Web/API/ Web_Components/使用_custom_elements
[注意:我已经删除了我最初发布的代码,因为它不安全,不仅不清楚而且实际上没有用:例如我在尝试它的变体时成功地使 TS 游乐场崩溃了。]