TypeScript-'元素'不可分配给HTMLInputElement

Yus*_*ick 5 javascript types typescript reactjs

我正在使用TypeScript和React。在我的组件(即对话框窗口)中,我想将触发元素(例如按钮)存储为属性。当组件卸下时,我想将焦点返回到该元素。但是,我从TSLint收到一个错误,我不确定如何解决。

class Dialog extends React.Component<Props, {}> {
  ...
  focusedElementBeforeDialogOpened: HTMLInputElement;

  componentDidMount() {
    this.focusedElementBeforeDialogOpened = document.activeElement;
    ...
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

我在分配属性值的行上收到错误:

[ts] Type 'Element' is not assignable to type 'HTMLInputElement'.
  Property 'accept' is missing in type 'Element'.
Run Code Online (Sandbox Code Playgroud)

但是,如果我将属性的类型更改为,Element甚至HTMLInputElement收到错误消息,componentWillUnmount()

componentWillUnmount() {
    ...
    this.focusedElementBeforeDialogOpened.focus();
}
Run Code Online (Sandbox Code Playgroud)

此错误是关于没有focus()方法的元素类型。

有没有办法告诉TypeScript document.activeElement应该是输入类型?就像是

this.focusedElementBeforeDialogOpened = <HTMLInputElement>document.activeElement;

还是有更好的方法解决这个问题,所以声明同时支持document.activeElement和的类型.focus()

Joh*_*isz 5

来自document.activeElement的文档:

如果当时有文本选择,通常会返回一个<input>or对象。<textarea>如果是这样,您可以使用元素的 SelectionStart 和 SelectionEnd 属性来获取更多详细信息。其他时候,焦点元素可能是<select>元素(菜单)或<input>按钮、复选框或单选类型的元素。

也就是说,document.activeElement不一定是 的实例HTMLInputElement(也可以是HTMLSelectElement等)。

如果您确实只是在寻找HTMLInputElement,您可以使用一个简单的instanceof类型保护,它可以被 TypeScript 识别:

componentDidMount() {
    if (document.activeElement instanceof HTMLInputElement) {
        this.focusedElementBeforeDialogOpened = document.activeElement;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

此外,您可以检测元素是否可聚焦,例如通过定义自己的类型保护:

interface IFocusableElement {
    focus(): void;
}

function isFocusable(element: any): element is IFocusableElement {
    return (typeof element.focus === "function");
}
Run Code Online (Sandbox Code Playgroud)

然后用作您自己的类型保护IFocusableElement的类型:this.focusedElementBeforeDialogOpened

focusedElementBeforeDialogOpened: IFocusableElement;

componentDidMount() {
    if (document.activeElement && isFocusable(document.activeElement)) {
        this.focusedElementBeforeDialogOpened = document.activeElement;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果你还需要 提供的原始 API Element,你可以只使用交集类型:

focusedElementBeforeDialogOpened: IFocusableElement & Element;
Run Code Online (Sandbox Code Playgroud)