为什么 Event.target 不是 Typescript 中的元素?

Why is Event.target not Element in Typescript?

我只想用我的 KeyboardEvent

var tag = evt.target.tagName.toLowerCase();

虽然 Event.targetEventTarget 类型,但它不继承自 Element。所以我必须这样投:

var tag = (<Element>evt.target).tagName.toLowerCase();

这可能是因为某些浏览器不符合标准,对吧? TypeScript 中与浏览器无关的正确实现是什么?

P.S。我正在使用 jQuery 来捕获 KeyboardEvent

它不继承自Element,因为并非所有事件目标都是元素。

From MDN:

Element, document, and window are the most common event targets, but other objects can be event targets too, for example XMLHttpRequest, AudioNode, AudioContext, and others.

即使您尝试使用的 KeyboardEvent 也可能出现在 DOM 元素或 window 对象上(理论上也可能出现在其他对象上),所以就在那里它不会将 evt.target 定义为 Element.

没有意义

如果它是 DOM 元素上的事件,那么我会说您可以安全地假设 evt.target。是一个 Element。我不认为这是跨浏览器行为的问题。只是 EventTarget 是一个比 Element.

更抽象的接口

进一步阅读:https://github.com/Microsoft/TypeScript/issues/29540

使用打字稿,我使用了一个只适用于我的函数的自定义界面。示例用例。

  handleChange(event: { target: HTMLInputElement; }) {
    this.setState({ value: event.target.value });
  }

在这种情况下,handleChange 将接收一个目标字段为 HTMLInputElement 类型的对象。

稍后在我的代码中我可以使用

<input type='text' value={this.state.value} onChange={this.handleChange} />

更简洁的方法是将界面放入单独的文件中。

interface HandleNameChangeInterface {
  target: HTMLInputElement;
}

然后使用下面的函数定义:

  handleChange(event: HandleNameChangeInterface) {
    this.setState({ value: event.target.value });
  }

在我的用例中,明确定义 handleChange 的唯一调用方是输入文本的 HTML 元素类型。

JLRishe 的回答是正确的,所以我只是在我的事件处理程序中使用它:

if (event.target instanceof Element) { /*...*/ }

打字稿 3.2.4

要检索 属性,您必须将目标转换为适当的数据类型:

e => console.log((e.target as Element).id)

@Bangonkali 提供了正确的答案,但这种语法似乎更具可读性,对我来说也更好:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}

使用打字稿,我们可以利用类型别名,如下所示:

type KeyboardEvent = {
  target: HTMLInputElement,
  key: string,
};
const onKeyPress = (e: KeyboardEvent) => {
  if ('Enter' === e.key) { // Enter keyboard was pressed!
    submit(e.target.value);
    e.target.value = '';
    return;
  }
  // continue handle onKeyPress input events...
};

您能否创建自己的扩展 Event 的通用接口。是这样的吗?

interface DOMEvent<T extends EventTarget> extends Event {
  readonly target: T
}

然后你可以像这样使用它:

handleChange(event: DOMEvent<HTMLInputElement>) {
  this.setState({ value: event.target.value });
}

我用这个:

onClick({ target }: MouseEvent) => {
    const targetDivElement: HTMLDivElement = target as HTMLDivElement;
    
    const listFullHeight: number = targetDivElement.scrollHeight;
    const listVisibleHeight: number = targetDivElement.offsetHeight;
    const listTopScroll: number = targetDivElement.scrollTop;
    }

我在处理来自 input 字段的事件时通常会遇到这个问题,例如按键。但请记住,该事件可能源于任何地方,例如来自 document 上的 keyup 侦听器,其中没有关联的 value。因此,为了正确提供信息,我会提供一个额外的类型:

interface KeyboardEventOnInputField extends KeyboardEvent {
  target: HTMLInputElement;
}
...

  onKeyUp(e: KeyboardEventOnInputField) {
    const inputValue = e.target.value;
    ...
  }

如果函数的输入类型为 Event,您可能需要告诉打字稿它实际上是什么:

  onKeyUp(e: Event) {
    const evt = e as KeyboardEventOnInputField;
    const inputValue = evt.target.value;
    this.inputValue.next(inputValue);
  }

这在 Angular 中是必需的,例如

对于 Angular 10+ 用户

只需声明 HTML 输入元素并将其扩展以将目标用作对象,就像我在下面为我的 bootstrap 4+ 文件浏览器输入所做的那样。这样可以省去很多工作。

  selectFile(event: HTMLInputElement & { target: HTMLInputElement}) {
    console.log(event.target.files);
    this.selectedFile = event.target.files[0];
  }