Pourquoi Event.target n'est-il pas un élément dans Typescript?


116

Je veux simplement faire cela avec mon KeyboardEvent

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

Bien que Event.target soit de type EventTarget, il n'hérite pas de Element. Je dois donc le lancer comme ceci:

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

Cela est probablement dû au fait que certains navigateurs ne respectent pas les normes, non? Quelle est la bonne implémentation indépendante du navigateur dans TypeScript?

PS: J'utilise jQuery pour capturer le KeyboardEvent.


7
Syntaxe un peu plus proprevar element = ev.target as HTMLElement
Adrian Moisa

Réponses:


57

Il n'hérite pas de Elementcar toutes les cibles d'événements ne sont pas des éléments.

De MDN :

L'élément, le document et la fenêtre sont les cibles d'événements les plus courantes, mais d'autres objets peuvent également être des cibles d'événements, par exemple XMLHttpRequest, AudioNode, AudioContext et autres.

Même ce KeyboardEventque vous essayez d'utiliser peut se produire sur un élément DOM ou sur l'objet window (et théoriquement sur d'autres choses), donc là, cela n'aurait pas de sens evt.targetd'être défini comme un Element.

S'il s'agit d'un événement sur un élément DOM, je dirais que vous pouvez supposer en toute sécurité evt.target. est un Element. Je ne pense pas que ce soit une question de comportement entre navigateurs. C'est simplement EventTargetune interface plus abstraite que Element.

Lectures complémentaires: https://typescript.codeplex.com/discussions/432211


8
Dans ce cas, KeyboardEvent et MouseEvent doivent avoir leur propre équivalent d'EventTarget qui contiendra toujours l'élément associé. DOM est tellement douteux ...: /
daniel.sedlacek

7
Je ne suis pas un expert du DOM ni de TypeScript mais je dirais que la conception de l'EventTarget a trop d'ambiguïté et que cela n'a rien à voir avec TypeScript.
daniel.sedlacek

2
@ daniel.sedlacek D'un autre côté, KeyboardEvents peut se produire à la fois sur les éléments DOM et sur l'objet window (et théoriquement d'autres choses), il est donc impossible de donner KeyboardEvent.targetun type qui soit plus spécifique que EventTarget, à moins que vous ne pensiez qu'il KeyboardEventdevrait également être un générique KeyboardEvent<T extends EventTarget>et aimerait être obligé de KeyboardEvent<Element>tout mettre dans votre code. À ce stade, vous feriez mieux de simplement faire le casting explicite, aussi douloureux que cela puisse être.
JLRishe

14
Dans le cas où cela serait utile pour quelqu'un d'autre à l'avenir, je devais effectuer un cast en tant que type d'élément spécifique afin d'accéder à la valuepropriété d'une <select>balise. eglet target = <HTMLSelectElement> evt.target;
munsellj

1
@munsellj (malheureusement) c'est la bonne façon de gérer les ambiguïtés dans un environnement typé.
pilau

47

En utilisant du typographie, j'utilise une interface personnalisée qui ne s'applique qu'à ma fonction. Exemple de cas d'utilisation.

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

Dans ce cas, le handleChange recevra un objet avec un champ cible de type HTMLInputElement.

Plus tard dans mon code, je peux utiliser

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

Une approche plus propre consisterait à placer l'interface dans un fichier séparé.

interface HandleNameChangeInterface {
  target: HTMLInputElement;
}

puis utilisez plus tard la définition de fonction suivante:

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

Dans mon cas d'utilisation, il est expressément défini que le seul appelant à handleChange est un type d'élément HTML de texte d'entrée.


Cela a parfaitement fonctionné pour moi - j'essayais toutes sortes de méchancetés, étendant EventTarget, etc. mais c'est la solution la plus propre +1
Kitson

1
Juste pour ajouter à cela, si vous avez besoin d'étendre la définition de l'événement, vous pouvez faire quelque chose comme ceci:handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement> & { target: HTMLInputElement }) => {...}
Kitson

41

La réponse de JLRishe est correcte, donc j'utilise simplement ceci dans mon gestionnaire d'événements:

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

28

Typographie 3.2.4

Pour récupérer la propriété, vous devez convertir la cible en type de données approprié:

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

Est-ce la même chose que la <HTMLInputElement>event.target;syntaxe?
Konrad Viltersten

@KonradViltersten, ils font la même chose. La assyntaxe a été introduite car elle était en conflit avec JSX. Il est recommandé d'utiliser aspour la cohérence. basarat.gitbooks.io/typescript/docs/types/type-assertion.html
Adam le

Aha je vois. Il semble également plus C # 'ish, ce qui dans de nombreux cas est un avantage, en fonction de l'expérience backend de l'équipe. Tant que ce n'est pas un de ces faux amis où la syntaxe ressemble à quelque chose mais implique quelque chose de totalement différent techniquement. (Je pense var et const entre Angular et C #, une triste expérience de la mienne, hehe).
Konrad Viltersten

2

Pourriez-vous créer votre propre interface générique qui s'étend Event. Quelque chose comme ça?

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

Ensuite, vous pouvez l'utiliser comme:

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

1

Avec typescript, nous pouvons exploiter les alias de type, comme ceci:

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 fournit la bonne réponse, mais cette syntaxe me semble plus lisible et juste plus agréable:

eventChange($event: KeyboardEvent): void {
    (<HTMLInputElement>$event.target).value;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.