Entrée typographique onchange event.target.value


143

Dans ma réaction et l' application tapuscrit, je l' utilise: onChange={(e) => data.motto = (e.target as any).value}.

Comment définir correctement les typages de la classe, pour ne pas avoir à me frayer un chemin dans le système de types avec any?

export interface InputProps extends React.HTMLProps<Input> {
...

}

export class Input extends React.Component<InputProps, {}> {
}

Si je mets target: { value: string };j'obtiens:

ERROR in [default] /react-onsenui.d.ts:87:18
Interface 'InputProps' incorrectly extends interface 'HTMLProps<Input>'.
  Types of property 'target' are incompatible.
    Type '{ value: string; }' is not assignable to type 'string'.

Réponses:


244

En général, les gestionnaires d'événements devraient utiliser e.currentTarget.value, par exemple:

onChange = (e: React.FormEvent<HTMLInputElement>) => {
    const newValue = e.currentTarget.value;
}

Vous pouvez lire pourquoi ici ( Revert "Rendre SyntheticEvent.target générique, pas SyntheticEvent.currentTarget." ).

UPD: Comme mentionné par @ roger-gusmao, ChangeEventplus approprié pour taper des événements de formulaire.

onChange = (e: React.ChangeEvent<HTMLInputElement>)=> {
   const newValue = e.target.value;
}

17
Cela ne fonctionne tout simplement pas. value n'est pas une propriété de l'interface EventTarget
tocqueville

1
Bien sûr que non EventTarget, mais une partie de HTMLInputElement Vous pouvez voir la définition complète ici github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/...
Yozi

1
Oh désolé, vous avez utilisé currentTarget. Dans ce cas oui, ça marche, mais la question portait surtarget
tocqueville

1
Oui, vous avez raison, mais comme mentionné dans github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 en utilisant targetincorrect dans la plupart des cas. De plus, la cible n'a pas Tà nous forcer à écrire correctement
Yozi

1
Cela n'a pas fonctionné pour moi, j'ai dû lancer l'événement React.ChangeEvent<HTMLInputElement>plutôt qu'un FormEvent.
Oblivionkey3

86

la bonne façon d'utiliser dans TypeScript est

  handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    // No longer need to cast to any - hooray for react!
    this.setState({temperature: e.target.value});
  }

  render() {
        ...
        <input value={temperature} onChange={this.handleChange} />
        ...
    );
  }

Suivez le cours complet, il vaut mieux comprendre:

import * as React from "react";

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};


interface TemperatureState {
   temperature: string;
}

interface TemperatureProps {
   scale: string;

}

class TemperatureInput extends React.Component<TemperatureProps, TemperatureState> {
  constructor(props: TemperatureProps) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }

  //  handleChange(e: { target: { value: string; }; }) {
  //    this.setState({temperature: e.target.value});  
  //  }


  handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    // No longer need to cast to any - hooray for react!
    this.setState({temperature: e.target.value});
  }

  render() {
    const temperature = this.state.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature} onChange={this.handleChange} />
      </fieldset>
    );
  }
}

export default TemperatureInput;

3
Note: pour assurer les types sont disponibles, ajoutez lib: ["dom"]à compilerOptionsentsconfig.json
James Conkling

1
@JamesConkling Merci beaucoup!
Alexandre Rivest

1
Et si vous avez plusieurs entrées, devez-vous créer une ligne pour chacune?
Trevor Wood

Une autre façon de s'assurer que 'this' est correctement attribué dans la fonction handleChange serait d'écrire handleChange comme une fonction de flèche, c'est-à-dire handleChange = (e: React.ChangeEvent <HTMLInputElement>) => {this.setState (...); }; En faisant cela, on n'aurait plus à utiliser le constructeur pour lier la fonction handleEvent.
tlavarea

Une autre façon de gérer 'this' au lieu d'utiliser le constructeur et la méthode de liaison serait d'utiliser la fonction de flèche dans le prop onChange ie onChange = {e => this.handleChange (e)}
tlavarea


9

Le que targetvous avez essayé d'ajouter InputPropsn'est pas le même que targetvous vouliez qui estReact.FormEvent

Donc, la solution que j'ai pu trouver était d'étendre les types liés aux événements pour ajouter votre type de cible, comme:

interface MyEventTarget extends EventTarget {
    value: string
}

interface MyFormEvent<T> extends React.FormEvent<T> {
    target: MyEventTarget
}

interface InputProps extends React.HTMLProps<Input> {
    onChange?: React.EventHandler<MyFormEvent<Input>>;
}

Une fois que vous avez ces classes, vous pouvez utiliser votre composant d'entrée comme

<Input onChange={e => alert(e.target.value)} />

sans erreurs de compilation. En fait, vous pouvez également utiliser les deux premières interfaces ci-dessus pour vos autres composants.


Le type de valeur n'est pas une chaîne!
Roger Gusmao

7

chanceux je trouve une solution. vous pouvez

import {ChangeEvent} de 'react';

puis écrivez du code comme: e:ChangeEvent<HTMLInputElement>


2

Voici une méthode de déstructuration d'objets ES6, testée avec TS 3.3.
Cet exemple concerne une saisie de texte.

name: string = '';

private updateName({ target }: { target: HTMLInputElement }) {
    this.name = target.value;
}

1

C'est lorsque vous travaillez avec un FileListobjet:

onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
  const fileListObj: FileList | null = event.target.files;
  if (Object.keys(fileListObj as Object).length > 3) {
    alert('Only three images pleaseeeee :)');
  } else {
    // Do something
  }

  return;
}}

1
  function handle_change(
    evt: React.ChangeEvent<HTMLInputElement>
  ): string {
    evt.persist(); // This is needed so you can actually get the currentTarget
    const inputValue = evt.currentTarget.value;

    return inputValue
  }

Et assurez-vous d'avoir "lib": ["dom"]dans votre fichier tsconfig.


1

Lors de l'utilisation du composant enfant, nous vérifions le type comme ceci.

Composant parent:

export default () => {

  const onChangeHandler = ((e: React.ChangeEvent<HTMLInputElement>): void => {
    console.log(e.currentTarget.value)
  }

  return (
    <div>
      <Input onChange={onChangeHandler} />
    </div>
  );
}

Composant enfant:

type Props = {
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
}

export Input:React.FC<Props> ({onChange}) => (
  <input type="tex" onChange={onChange} />
)

0

Une alternative qui n'a pas encore été mentionnée est de taper la fonction onChange au lieu des accessoires qu'elle reçoit. Utilisation de React.ChangeEventHandler:

const stateChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
    console.log(event.target.value);
};

-1

Merci @haind

Oui a HTMLInputElementtravaillé pour le champ de saisie

//Example
var elem = e.currentTarget as HTMLInputElement;
elem.setAttribute('my-attribute','my value');
elem.value='5';

Il HTMLInputElements'agit d'une interface HTMLElementhéritée de laquelle est héritée EventTargetau niveau racine. Par conséquent, nous pouvons affirmer en utilisant un asopérateur d'utiliser des interfaces spécifiques en fonction du contexte, comme dans ce cas, nous utilisons HTMLInputElementpour le champ de saisie d'autres interfaces HTMLButtonElement, HTMLImageElementetc.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement

Pour plus de références, vous pouvez consulter une autre interface disponible ici

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.