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


115

我只是想用KeyboardEvent做到这一点

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

尽管Event.target的类型为EventTarget,但它并不继承自Element。因此,我必须像这样强制转换:

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

这可能是由于某些浏览器未遵循标准,对吗?TypeScript中与浏览器无关的正确实现是什么?

PS:我使用jQuery捕获KeyboardEvent。


7
语法更var element = ev.target as HTMLElement
简洁

Answers:


57

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

从MDN

元素,文档和窗口是最常见的事件目标,但是其他对象也可以是事件目标,例如XMLHttpRequest,AudioNode,AudioContext等。

即使KeyboardEvent您尝试使用的对象,也可能出现在DOM元素或window对象上(理论上是在其他事物上),因此在此处将evt.target其定义为没什么意义Element

如果这是DOM元素上的事件,那么我可以肯定地说evt.target。是一个Element。我认为这与跨浏览器的行为无关。只是那EventTarget是一个比更加抽象的接口Element

进一步阅读:https : //typescript.codeplex.com/discussions/432211


8
在这种情况下,KeyboardEvent和MouseEvent应该具有与EventTarget相同的属性,并将始终包含关联的Element。DOM太狡猾了……:/
daniel.sedlacek 2015年

7
我不是DOM或TypeScript方面的专家,但我想说EventTarget的设计含糊不清,与TypeScript无关。
daniel.sedlacek 2015年

2
@ daniel.sedlacek另一方面,KeyboardEvents可以同时出现在DOM元素和窗口对象上(以及从理论上讲是其他事情),因此,不可能给出KeyboardEvent.target比更加具体的类型EventTarget,除非您认为KeyboardEvent也应该是泛型类型,KeyboardEvent<T extends EventTarget>并希望被迫将KeyboardEvent<Element>所有内容放入整个代码中。那时,最好还是进行显式转换,尽管可能会很痛苦。
JLRishe'3

14
如果将来对其他人有帮助,我需要将其强制转换为特定的元素类型,以便访问标记的value属性<select>。例如let target = <HTMLSelectElement> evt.target;
munsellj,2016年

1
@munsellj(不幸的是)是处理类型化环境中歧义的正确方法。
pilau

47

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

  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元素类型。


这对我来说非常有效-我正在尝试各种方法,扩展EventTarget等。但这是最干净的解决方案+1
Kitson

1
除此之外,如果您需要扩展事件定义,则可以执行以下操作:handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement> & { target: HTMLInputElement }) => {...}
Kitson

40

JLRishe的答案是正确的,因此我只在事件处理程序中使用它:

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

28

打字稿3.2.4

要检索属性,必须将target强制转换为适当的数据类型:

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

这与<HTMLInputElement>event.target;语法相同吗?
康拉德·维特尔斯滕

@KonradViltersten,他们做同样的事情。在as介绍语法,因为它与JSX冲突。建议使用as以保持一致性。basarat.gitbooks.io/typescript/docs/types/type-assertion.html
亚当

啊哈,我明白了。它还显示出更多的C#效果,这在很多情况下是一个优势,具体取决于团队的后端经验。只要不是那些语法相似但在技术上暗示完全不同的虚假朋友之一。(我想在Angular和C#之间使用varconst,这是我的悲惨经历,呵呵)。
康拉德·维特尔斯滕

2

您可以创建自己的扩展通用接口吗Event?像这样吗

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

然后,您可以像这样使用它:

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

1

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

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...
};

0

@Bangonkali提供了正确的答案,但是这种语法似乎更易读,对我而言更好:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.