Чому Event.target не є елементом у Typescript?


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
Адріана Моїса

Відповіді:


57

Це не успадковується з-за того, Elementщо не всі цілі події є елементами.

Від MDN :

Елемент, документ і вікно - найпоширеніші цілі подій, але інші об'єкти можуть бути і цілями подій, наприклад XMLHttpRequest, AudioNode, AudioContext та інші.

Навіть те, KeyboardEventщо ви намагаєтеся використовувати, може виникнути на елементі DOM або на об'єкті вікна (і теоретично на інших речах), тому прямо там не було б сенсу evt.targetвизначатись якElement .

Якщо це подія на елементі DOM, то я б сказав, що ви можете сміливо припускати evt.target. є Element. Я не думаю, що це питання поведінки між веб-переглядачами. Просто EventTargetце більш абстрактний інтерфейс, ніжElement .

Подальше читання: https://typescript.codeplex.com/discussions/432211


8
У цьому випадку KeyboardEvent і MouseEvent повинні мати власний еквівалент EventTarget, який завжди буде містити пов'язаний Елемент. DOM так хитрий ...: /
daniel.sedlacek

7
Я не фахівець з DOM і TypeScript, але я б сказав, що дизайн EventTarget має надто багатозначність, і це не має нічого спільного з TypeScript.
daniel.sedlacek

2
@ daniel.sedlacek З іншого боку, KeyboardEvents може виникати як на елементах DOM, так і на об'єкті вікна (і теоретично інших речах), тому прямо там неможливо надати KeyboardEvent.targetтип, який є більш конкретним, ніж EventTarget, якщо ви не вважаєте, що KeyboardEventвін також повинен бути загальний тип, KeyboardEvent<T extends EventTarget>і хотіли б, щоб ви були змушені розміщувати KeyboardEvent<Element>все в коді. У цей момент вам краще просто робити чіткий склад, болісно, ​​хоча це може бути.
JLRishe

14
У випадках, які в майбутньому корисні для будь-кого іншого, мені потрібно було передати певний тип елемента, щоб отримати доступ до valueвластивості <select>тегу. наприкладlet target = <HTMLSelectElement> evt.target;
munsellj

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

У моєму випадку використання чітко визначено, що єдиним абонентом, що обробляєChange, є тип елемента HTML, що вводиться.


Це прекрасно працювало для мене - я намагався всілякі неприємності, розширював EventTarget і т. Д., Але це найчистіше рішення +1
Кітсон

1
Просто додайте до цього, якщо вам потрібно розширити визначення події, ви можете зробити щось подібне:handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement> & { target: HTMLInputElement }) => {...}
Кітсон

41

Відповідь JLRishe правильна, тому я просто використовую це у своєму обробнику подій:

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

28

Машинопис 3.2.4

Для отримання властивості ви повинні націлити ціль на відповідний тип даних:

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 # 'ish, що в багатьох випадках є перевагою, залежно від досвіду роботи команди. Поки це не один з тих хибних друзів, де синтаксис нагадує щось, але технічно передбачає щось зовсім інше. (Я думаю, що вар і const між Angular і C #, сумний мій досвід, хе-хе).
Конрад Вільтерстен

2

Чи можете ви створити власний загальний інтерфейс, який розширюється Event. Щось на зразок цього?

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

Тоді ви можете використовувати його так:

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

1

За допомогою typecript ми можемо використовувати псевдоніми типу:

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.