Lit element typescript 项目全局接口声明有必要吗?

Lit element typescript project global interface declaration necessary?

Typescript Lit Element starter project 在示例元素的底部包含此全局接口声明:

declare global {
  interface HTMLElementTagNameMap {
    'my-element': MyElement;
  }
}

有必要吗?它有什么用?

Is that necessary?

不,此声明不是您基于 LitElement 的自定义元素工作所必需的。

What is it used for?

这是 TypeScript 的一项功能,并非特定于 LitElement。

此声明有助于 TypeScript 在与 DOM API 交互时提供强类型。 JavaScript DOM API 当然不知道或不关心类型,但 TypeScript 知道。使用此机制,您可以将自定义元素的类型添加到 DOM APIs.

举个例子可能会更好地说明这一点。假设这个非常简单的自定义元素:

class HelloWorldElement extends HTMLElement {

  name = 'world'; // public 'name' member with default value

  // ... element internals left aside,
  // just assume this.name is used somewhere ...
}

window.customElements.define('hello-world', HelloWorldElement);

现在考虑将此元素与 DOM APIs:

一起使用
const el = document.createElement('hello-world');

// el has the very generic type HTMLElement
el.name = 'custom elements';  // error! HTMLElement has no member 'name'

TypeScript 不允许。它无法(还)知道标签名称 hello-worldHelloWorldElement 实例一起使用,因为 customElements.define(...) 语句在运行时执行,但在编译时检查类型安全。

但是如果你扩展 HTMLElementTagNameMap 的声明,TypeScript 将知道 <hello-world></hello-world> 元素的类型:

// with the added declaration
declare global {
  interface HTMLElementTagNameMap {
    'hello-world': HelloWorldElement;
  }
}

const el = document.createElement('hello-world');
// el has type HelloWorldElement
el.name = 'custom elements';  // OK. HelloWorldElement has a string member 'name'

如果您想了解更多详细信息,可以在 TypeScript Handbook 中找到它们。