Typescript: Tipos de eventos React

Cuál es el tipo correcto para los eventos de React. Inicialmente usaba any por razones de simplicidad. Ahora, estoy tratando de limpiar las cosas y evitar el uso de any por completo.

Así que en una forma simple como esta:

export interface LoginProps {
  login: {
    [k: string]: string | Function
    uname: string
    passw: string
    logIn: Function
  }
}
@inject('login') @observer
export class Login extends Component<LoginProps, {}> {
  update = (e: React.SyntheticEvent<EventTarget>): void => {
    this.props.login[e.target.name] = e.target.value
  }
  submit = (e: any): void => {
    this.props.login.logIn()
    e.preventDefault()
  }
  render() {
    const { uname, passw } = this.props.login
    return (
      <div id='login' >
        <form>
          <input
            placeholder='Username'
            type="text"
            name='uname'
            value={uname}
            onChange={this.update}
          />
          <input
            placeholder='Password'
            type="password"
            name='passw'
            value={passw}
            onChange={this.update}
          />
          <button type="submit" onClick={this.submit} >
            Submit
          </button>
        </form>
      </div>
    )
  }
}

¿Qué tipo utilizo aquí como tipo de evento?

React.SyntheticEvent<EventTarget<no parece funcionar ya que me da un error de que nombre y valor no existen en el target.

Se agradecería una respuesta más generalizada para todos los eventos.

Gracias

Solución

La interfaz SyntheticEvent es genérica:

interface SyntheticEvent {
    ...
    currentTarget: EventTarget & T;
    ...
}

Y el currentTarget es una intersección de la restricción genérica y el EventTarget.
Además, dado que tus eventos son causados por un elemento de entrada, deberías usar el FormEvent (en el archivo de definición, los documentos de react).

Debería ser:

update = (e: React.FormEvent): void => {
    this.props.login[e.currentTarget.name] = e.currentTarget.value
}
Comentarios (14)

El problema no es el tipo de evento, sino que la interfaz EventTarget en typescript sólo tiene 3 métodos:

interface EventTarget {
    addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
    dispatchEvent(evt: Event): boolean;
    removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}

interface SyntheticEvent {
    bubbles: boolean;
    cancelable: boolean;
    currentTarget: EventTarget;
    defaultPrevented: boolean;
    eventPhase: number;
    isTrusted: boolean;
    nativeEvent: Event;
    preventDefault(): void;
    stopPropagation(): void;
    target: EventTarget;
    timeStamp: Date;
    type: string;
}

Así que es correcto que name y value no existen en EventTarget. Lo que tienes que hacer es convertir el objetivo en el tipo de elemento específico con las propiedades que necesitas. En este caso será HTMLInputElement.

update = (e: React.SyntheticEvent): void => {
    let target = e.target as HTMLInputElement;
    this.props.login[target.name] = target.value;
}

También para los eventos, en lugar de React.SyntheticEvent, puedes escribirlos de la siguiente manera: Event, MouseEvent, KeyboardEvent...etc, depende del caso de uso del handler.

La mejor manera de ver todas estas definiciones de tipos es revisar los archivos .d.ts de ambos typescript & react.

También puedes consultar el siguiente enlace para más explicaciones: https://stackoverflow.com/questions/28900077/why-is-event-target-not-element-in-typescript

Comentarios (2)

Combinando las respuestas de Nitzan y Edwin, he descubierto que algo así me funciona:

update = (e: React.FormEvent): void => {
    let target = e.target as HTMLInputElement;
    this.props.login[target.name] = target.value;
}
Comentarios (0)