Definitelytyped: Torne React.SyntheticEvent.target genérico em vez de T, não React.SyntheticEvent.currentTarget

Criado em 26 set. 2016  ·  7Comentários  ·  Fonte: DefinitelyTyped/DefinitelyTyped

Atualmente, a assinatura do Typescript 2.0 para SyntheticEvent do React se parece com:

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

De acordo com o commit a13fa7abf55daedf25b31258b908548f55962c7a, target era originalmente EventTarget & T , mas esta alteração foi (aparentemente) acidentalmente revertida durante uma fusão no commit 5607f54defce88bc52a0440288f434cafffdb5ce.

A assinatura atual quebra muitos códigos pré-2.0 (como você pode imaginar, o código React está repleto de manipuladores de eventos) com pouco ou nenhum benefício (já que a maioria do código depende de event.target , então isso significa ainda depender de pré -2.0 código como (event.target as any).value , uma vez que event.target não é genérico.

Ficarei feliz em fornecer um patch, mas gostaria de ter certeza de que SyntheticEvent.target não foi desgenerificado de propósito.

Comentários muito úteis

Você nem sempre pode dizer o tipo de destino em tempo de compilação. Torná-lo genérico tem pouco valor.
target é a origem do evento (com o qual ninguém realmente se preocupa, pode ser um intervalo dentro de um link, por exemplo)
currentTarget é o elemento que possui o manipulador de eventos anexado, com o qual você deve se preocupar muito e digitar de acordo se anexou um conjunto de dados ou outros atributos a ele e pretende acessar em tempo de execução.

Depender do alvo em vez de currentTarget é um erro do iniciante que irá mordê-los mais cedo do que tarde.

Por exemplo:

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

Este código é usado para compilar, como deveria.

Com a 'correção' mesclada, e.currentTarget não é digitável (não consigo acessar seu conjunto de dados sem um erro de tipo) e e.target agora é digitado como um HTMLLinkElement, quando na verdade não há como podemos ter certeza sobre isso. (Posso ter clicado na extensão interna.

Teoricamente, poderíamos adicionar um segundo genérico a SyntheticEvent, para digitar target, quando o usuário tiver certeza disso (nenhum filho para o tratador de evento, ou todos têm o mesmo tipo). Mas é de pouco valor e realmente enganoso (porque se aplica apenas a casos específicos em que o uso de fundição faria muito mais sentido).
Em particular, se você não tem filhos, pode usar currentTarget.

Todos 7 comentários

Este é provavelmente um erro cometido durante a fusão. Por favor, faça um PR.

consulte # 11041, # 10784 e muitos mais. É um mistério o porquê de não ser corrigido mesmo após a fusão.

Você nem sempre pode dizer o tipo de destino em tempo de compilação. Torná-lo genérico tem pouco valor.
target é a origem do evento (com o qual ninguém realmente se preocupa, pode ser um intervalo dentro de um link, por exemplo)
currentTarget é o elemento que possui o manipulador de eventos anexado, com o qual você deve se preocupar muito e digitar de acordo se anexou um conjunto de dados ou outros atributos a ele e pretende acessar em tempo de execução.

Depender do alvo em vez de currentTarget é um erro do iniciante que irá mordê-los mais cedo do que tarde.

Por exemplo:

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

Este código é usado para compilar, como deveria.

Com a 'correção' mesclada, e.currentTarget não é digitável (não consigo acessar seu conjunto de dados sem um erro de tipo) e e.target agora é digitado como um HTMLLinkElement, quando na verdade não há como podemos ter certeza sobre isso. (Posso ter clicado na extensão interna.

Teoricamente, poderíamos adicionar um segundo genérico a SyntheticEvent, para digitar target, quando o usuário tiver certeza disso (nenhum filho para o tratador de evento, ou todos têm o mesmo tipo). Mas é de pouco valor e realmente enganoso (porque se aplica apenas a casos específicos em que o uso de fundição faria muito mais sentido).
Em particular, se você não tem filhos, pode usar currentTarget.

Além disso, está completamente errado, em um DOMAttributes<SomeType> , você obtém um onClick : MouseEventHandler<SomeType> , em seguida, obtém EventHandler<MouseEvent<SomeType>> com

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

Você absolutamente não pode digitar target diferente de currentTarget. onClick espera um manipulador de eventos que possui o evento de manipulação (também conhecido como currentTarget) como o genérico. Não pode ser outra coisa, não compilará.

@bbenezech

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

Em vez disso, sugiro:

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

Você também tem ClipboardEvent<T> , CompositionEvent<T> , DragEvent<T> , FocusEvent<T> , KeyboardEvent<T> ...
SyntheticEvent é a coisa de baixo nível.

Isso ainda é assim no repositório do NPM @types . Qualquer atualização sobre quando isso será publicado

Isso foi mudado de volta. Veja # 12239.

Esta página foi útil?
0 / 5 - 0 avaliações