Warum ist Event.target kein Element in Typescript?


115

Ich möchte dies einfach mit meinem KeyboardEvent tun

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

Während Event.target vom Typ EventTarget ist, erbt es nicht von Element. Also muss ich es so besetzen:

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

Dies liegt wahrscheinlich daran, dass einige Browser nicht den Standards entsprechen, oder? Was ist die richtige browserunabhängige Implementierung in TypeScript?

PS: Ich verwende jQuery, um das KeyboardEvent zu erfassen.


7
Etwas sauberere Syntaxvar element = ev.target as HTMLElement
Adrian Moisa

Antworten:


56

Es wird nicht geerbt, Elementda nicht alle Ereignisziele Elemente sind.

Von MDN :

Element, Dokument und Fenster sind die häufigsten Ereignisziele, aber auch andere Objekte können Ereignisziele sein, z. B. XMLHttpRequest, AudioNode, AudioContext und andere.

Sogar das, was KeyboardEventSie verwenden möchten, kann auf einem DOM-Element oder auf dem Fensterobjekt (und theoretisch auf anderen Dingen) auftreten, sodass es genau dort keinen Sinn macht evt.target, als definiert zu werden Element.

Wenn es sich um ein Ereignis in einem DOM-Element handelt, kann ich davon ausgehen, dass Sie davon ausgehen können evt.target. ist ein Element. Ich denke nicht, dass dies eine Frage des browserübergreifenden Verhaltens ist. Nur das EventTargetist eine abstraktere Schnittstelle als Element.

Weiterführende Literatur: https://typescript.codeplex.com/discussions/432211


8
In diesem Fall sollten KeyboardEvent und MouseEvent ein eigenes Äquivalent zu EventTarget haben, das immer das zugehörige Element enthält. DOM ist so zwielichtig ...: /
daniel.sedlacek

7
Ich bin kein Experte für DOM oder TypeScript, aber ich würde sagen, dass das Design des EventTargets zu vieldeutig ist und das nichts mit TypeScript zu tun hat.
daniel.sedlacek

2
@ daniel.sedlacek Andererseits kann KeyboardEvents sowohl auf DOM-Elementen als auch auf dem Fensterobjekt (und theoretisch anderen Dingen) auftreten, sodass es genau dort unmöglich ist, KeyboardEvent.targeteinen Typ anzugeben , der spezifischer ist als EventTarget, es sei denn, Sie denken, es KeyboardEventsollte auch ein sein generischer Typ KeyboardEvent<T extends EventTarget>und möchte gezwungen werden, KeyboardEvent<Element>alles in Ihren Code zu setzen. An diesem Punkt ist es besser, nur die explizite Besetzung zu machen, auch wenn es schmerzhaft sein mag.
JLRishe

14
In Fällen, in denen es für andere in Zukunft hilfreich ist, musste ich einen bestimmten Elementtyp verwenden, um auf die valueEigenschaft eines <select>Tags zugreifen zu können . zBlet target = <HTMLSelectElement> evt.target;
Munsellj

1
@munsellj (leider) das ist der richtige Weg, um mit Mehrdeutigkeiten in einer typisierten Umgebung umzugehen.
Pilau

47

Mit Typoskript verwende ich eine benutzerdefinierte Schnittstelle, die nur für meine Funktion gilt. Beispiel Anwendungsfall.

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

In diesem Fall erhält handleChange ein Objekt mit einem Zielfeld vom Typ HTMLInputElement.

Später in meinem Code kann ich verwenden

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

Ein sauberer Ansatz wäre, die Schnittstelle in eine separate Datei zu stellen.

interface HandleNameChangeInterface {
  target: HTMLInputElement;
}

Verwenden Sie später die folgende Funktionsdefinition:

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

In meinem Anwendungsfall wird ausdrücklich definiert, dass der einzige Aufrufer von handleChange ein HTML-Elementtyp des Eingabetextes ist.


Dies funktionierte perfekt für mich - ich habe alle möglichen Probleme versucht, EventTarget usw. erweitert, aber dies ist die sauberste Lösung +1
Kitson

1
Wenn Sie die Ereignisdefinition erweitern müssen, können Sie Folgendes tun:handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement> & { target: HTMLInputElement }) => {...}
Kitson

39

Die Antwort von JLRishe ist richtig, daher verwende ich diese einfach in meinem Event-Handler:

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

28

Typoskript 3.2.4

Zum Abrufen von Eigenschaften müssen Sie das Ziel in den entsprechenden Datentyp umwandeln:

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

Entspricht das der <HTMLInputElement>event.target;Syntax?
Konrad Viltersten

@KonradViltersten, sie machen das Gleiche. Die asSyntax wurde eingeführt, weil sie mit JSX in Konflikt stand. Es wird empfohlen, aus Gründen der asKonsistenz zu verwenden. basarat.gitbooks.io/typescript/docs/types/type-assertion.html
Adam

Aha, ich verstehe. Es erscheint auch mehr C # 'ish, was in vielen Fällen von Vorteil ist, abhängig von der Backend-Erfahrung des Teams. Solange es nicht einer dieser falschen Freunde ist, bei denen die Syntax etwas ähnelt, sondern technisch etwas völlig anderes impliziert. (Ich denke var und const zwischen Angular und C #, eine traurige Erfahrung von mir, hehe).
Konrad Viltersten

2

Könnten Sie Ihre eigene generische Schnittstelle erstellen, die sich erweitert Event? Etwas wie das?

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

Dann können Sie es wie folgt verwenden:

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

1

Mit Typoskript können wir Typ-Aliase wie folgt nutzen:

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 liefern die richtige Antwort, aber diese Syntax scheint mir lesbarer und nur schöner zu sein:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.