Definitelytyped: Rendre React.SyntheticEvent.target générique sur T, pas React.SyntheticEvent.currentTarget

Créé le 26 sept. 2016  ·  7Commentaires  ·  Source: DefinitelyTyped/DefinitelyTyped

Actuellement, la signature Typescript 2.0 pour le SyntheticEvent de React ressemble à :

interface SyntheticEvent<T> {
    currentTarget: EventTarget & T;
    target: EventTarget;
}

Selon le commit a13fa7abf55daedf25b31258b908548f55962c7a, target était à l'origine EventTarget & T , mais ce changement a (apparemment) été accidentellement annulé lors d'une fusion dans le commit 5607f54defce88bc52a0440288f434cafffdb5ce.

La signature actuelle casse beaucoup de code pré-2.0 (comme vous pouvez l'imaginer, le code React est rempli de gestionnaires d'événements) pour peu ou pas d'avantage (puisque la plupart du code repose sur event.target , cela signifie donc toujours compter sur pré -2.0 code comme (event.target as any).value , puisque event.target n'est pas générique.

Je serai heureux de fournir un correctif, mais j'aimerais être sûr que SyntheticEvent.target n'a pas été volontairement dégénéré.

Commentaire le plus utile

Vous ne pouvez pas toujours dire le type de la cible au moment de la compilation. Le rendre générique n'a que peu de valeur.
cible est l'origine de l'événement (dont personne ne se soucie vraiment, il peut s'agir d'un intervalle à l'intérieur d'un lien, par exemple)
currentTarget est l'élément auquel est attaché le gestionnaire d'événements, auquel vous devez faire très attention et taper en conséquence si vous lui avez attaché un ensemble de données ou d'autres attributs et que vous avez l'intention d'y accéder au moment de l'exécution.

Se fier à la cible au lieu de la cible actuelle est une erreur de débutant qui les mordra plus tôt que la dernière.

Par exemple:

  handleTabClick = (e: React.SyntheticEvent<HTMLLinkElement>) => {
    e.preventDefault()
    // !!! e.target.dataset is empty if user clicked the <span>, not the <a> !!!
    // !!! how can you type e.target? User might also have clicked the <a> if it has padding !!!
    // you have to use currentTarget, and it is the element that you know the type for sure
    if (e.currentTarget.dataset['closable'] === 'true') {
      this.close()
    }
  }

render() {
  return <a onClick={this.handleTabClick} data-closable="true">
      <span className="fatty">Click me!</span>
   </a>
}

Ce code utilisé pour compiler, comme il se doit.

Avec le 'fix' fusionné, e.currentTarget n'est pas typable (je ne peux pas accéder à son ensemble de données sans erreur de type) et e.target est maintenant tapé en tant que HTMLLinkElement, alors qu'en fait il n'y a aucun moyen on peut en être sûr. (J'ai peut-être cliqué sur la travée à l'intérieur.

Théoriquement, nous pourrions ajouter un deuxième générique à SyntheticEvent, pour taper target, lorsque l'utilisateur en est certain (pas d'enfants au gestionnaire d'événement, ou ils ont tous le même type). Mais c'est de peu de valeur et vraiment trompeur (car cela ne s'applique qu'à des cas particuliers où l'utilisation du casting aurait beaucoup plus de sens).
En particulier, si vous n'avez pas d'enfants, vous pouvez utiliser currentTarget.

Tous les 7 commentaires

Il s'agit probablement d'une erreur commise lors de la fusion. Merci de faire un PR.

voir #11041, #10784 et bien d'autres. C'est un mystère pourquoi il n'est pas corrigé même après la fusion.

Vous ne pouvez pas toujours dire le type de la cible au moment de la compilation. Le rendre générique n'a que peu de valeur.
cible est l'origine de l'événement (dont personne ne se soucie vraiment, il peut s'agir d'un intervalle à l'intérieur d'un lien, par exemple)
currentTarget est l'élément auquel est attaché le gestionnaire d'événements, auquel vous devez faire très attention et taper en conséquence si vous lui avez attaché un ensemble de données ou d'autres attributs et que vous avez l'intention d'y accéder au moment de l'exécution.

Se fier à la cible au lieu de la cible actuelle est une erreur de débutant qui les mordra plus tôt que la dernière.

Par exemple:

  handleTabClick = (e: React.SyntheticEvent<HTMLLinkElement>) => {
    e.preventDefault()
    // !!! e.target.dataset is empty if user clicked the <span>, not the <a> !!!
    // !!! how can you type e.target? User might also have clicked the <a> if it has padding !!!
    // you have to use currentTarget, and it is the element that you know the type for sure
    if (e.currentTarget.dataset['closable'] === 'true') {
      this.close()
    }
  }

render() {
  return <a onClick={this.handleTabClick} data-closable="true">
      <span className="fatty">Click me!</span>
   </a>
}

Ce code utilisé pour compiler, comme il se doit.

Avec le 'fix' fusionné, e.currentTarget n'est pas typable (je ne peux pas accéder à son ensemble de données sans erreur de type) et e.target est maintenant tapé en tant que HTMLLinkElement, alors qu'en fait il n'y a aucun moyen on peut en être sûr. (J'ai peut-être cliqué sur la travée à l'intérieur.

Théoriquement, nous pourrions ajouter un deuxième générique à SyntheticEvent, pour taper target, lorsque l'utilisateur en est certain (pas d'enfants au gestionnaire d'événement, ou ils ont tous le même type). Mais c'est de peu de valeur et vraiment trompeur (car cela ne s'applique qu'à des cas particuliers où l'utilisation du casting aurait beaucoup plus de sens).
En particulier, si vous n'avez pas d'enfants, vous pouvez utiliser currentTarget.

De plus, c'est complètement faux, sur un DOMAttributes<SomeType> , vous obtenez un onClick : MouseEventHandler<SomeType> , puis obtenez EventHandler<MouseEvent<SomeType>> avec

    interface EventHandler<E extends SyntheticEvent<any>> {
        (event: E): void;
    }

Vous ne pouvez absolument pas taper target différemment de currentTarget. onClick attend un gestionnaire d'événements qui a un événement de gestion (alias currentTarget) comme générique. Ça ne peut pas être autre chose, ça ne compilera pas.

@bbenezech

handleTabClick = (e: React.SyntheticEvent<HTMLLinkElement>) => { ... }

Je suggère à la place :

handleTabClick = (e: React.FormEvent<HTMLLinkElement>) => { ... }

Vous avez également ClipboardEvent<T> , CompositionEvent<T> , DragEvent<T> , FocusEvent<T> , KeyboardEvent<T> ...
SyntheticEvent est la chose de bas niveau.

C'est toujours comme ça sur le référentiel @types NPM. Toute mise à jour sur le moment où cela sera publié

Cela a été changé en arrière. Voir #12239.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

JWT
svipas picture svipas  ·  3Commentaires

fasatrix picture fasatrix  ·  3Commentaires

jrmcdona picture jrmcdona  ·  3Commentaires

alisabzevari picture alisabzevari  ·  3Commentaires

JudeAlquiza picture JudeAlquiza  ·  3Commentaires