我正在使用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();
}
此错误与Element类型没有focus()
方法有关。
问题
有没有办法告诉TypeScript document.activeElement
应该是输入类型?像
this.focusedElementBeforeDialogOpened = <HTMLInputElement>document.activeElement;
或者是否有更好的解决方法,因此声明支持document.activeElement
和.focus()
的类型?
答案 0 :(得分:1)
来自document.activeElement的文档:
如果此对象具有文本选择,通常会返回
<input>
或<textarea>
对象。如果是这样,您可以使用元素的selectionStart和selectionEnd属性获得更多细节。其他时候,focus元素可能是<select>
元素(菜单)或<input>
元素,类型为button,checkbox或radio。
也就是说,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;
答案 1 :(得分:0)
实际上,lib.es6.d.ts
中的定义有点不一致,除非它的W3C规范有点令人困惑:
interface Document extends [...] {
/**
* Gets the object that has the focus when the parent document has focus.
*/
readonly activeElement: Element;
[...]
focus(): void;
[...]
}
interface HTMLElement extends Element {
[...]
focus(): void;
[...]
}
因此,我们可以手动关注的仅有的两种对象是Document
和HtmlElement
,但任何Element
都可以集中注意力!
如果您只需要回馈焦点,可以执行以下操作:
class Dialog extends React.Component<Props, {}> {
private resetFocus = () => {};
componentDidMount() {
const elementToFocus = document.activeElement instanceof HTMLElement
? document.activeElement
: document;
this.resetFocus = () => elementToFocus.focus();
}
componentWillUnmount() {
this.resetFocus();
}
}
或
componentDidMount() {
const activeElement = document.activeElement as any;
if (typeof activeElement.focus === 'function') {
this.resetFocus = () => activeElement.focus();
}
}