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

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

  componentDidMount() {
    this.focusedElementBeforeDialogOpened = document.activeElement;
    ...
  }
  ...
}

我在分配属性值的行上收到错误:
[ts] Type 'Element' is not assignable to type 'HTMLInputElement'.
  Property 'accept' is missing in type 'Element'.

但是,如果我将属性的类型更改为Element甚至HTMLInputElement,我会在componentWillUnmount()中收到错误消息
componentWillUnmount() {
    ...
    this.focusedElementBeforeDialogOpened.focus();
}

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

问题

有没有办法告诉TypeScript document.activeElement应该是输入类型?就像是
this.focusedElementBeforeDialogOpened = <HTMLInputElement>document.activeElement;
还是有更好的方法解决这个问题,所以声明支持document.activeElement.focus()的类型?

最佳答案

document.activeElement的文档中:



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

如果您确实只在寻找HTMLInputElement,则可以使用TypeScript可以识别的简单instanceof类型防护:

componentDidMount() {
    if (document.activeElement instanceof HTMLInputElement) {
        this.focusedElementBeforeDialogOpened = document.activeElement;
    }
    ...
}

此外,您可以检测元素是否可聚焦,例如通过定义自己的类型保护:
interface IFocusableElement {
    focus(): void;
}

function isFocusable(element: any): element is IFocusableElement {
    return (typeof element.focus === "function");
}

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

componentDidMount() {
    if (document.activeElement && isFocusable(document.activeElement)) {
        this.focusedElementBeforeDialogOpened = document.activeElement;
    }
    ...
}

如果您还需要Element提供的原始API,则可以使用交集类型:
focusedElementBeforeDialogOpened: IFocusableElement & Element;

09-18 05:29