Typoskript-Eingabe onchange event.target.value


141

In meiner React- und Typoskript-App verwende ich : onChange={(e) => data.motto = (e.target as any).value}.

Wie definiere ich die Typisierungen für die Klasse richtig, damit ich mich nicht mit dem Typensystem herumhacken muss any?

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

}

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

Wenn ich target: { value: string };sage, bekomme ich:

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'.

Antworten:


243

Im Allgemeinen sollten Event-Handler Folgendes verwenden e.currentTarget.value, z.

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

Lesen Sie hier, warum dies so ist ( Setzen Sie "SyntheticEvent.target generisch machen, nicht SyntheticEvent.currentTarget." ).

UPD: Wie von @ roger-gusmao erwähnt, ChangeEventbesser geeignet für die Eingabe von Formularereignissen.

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

17
Das funktioniert einfach nicht. Wert ist keine Eigenschaft der Schnittstelle EventTarget
tocqueville

1
Natürlich nicht EventTarget, sondern Teil von HTMLInputElement. Die vollständige Definition finden Sie hier. Github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/…
Yozi

1
Oh, tut mir leid, du hast es benutzt currentTarget. In diesem Fall ja, es funktioniert, aber die Frage war übertarget
tocqueville

1
Ja, Sie haben Recht, aber wie in github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 erwähnt , targetwird in den meisten Fällen eine falsche Verwendung verwendet. Darüber hinaus muss das Ziel uns nicht Tzwingen, richtig zu schreiben
Yozi

1
Das hat bei mir nicht funktioniert, ich musste das Event React.ChangeEvent<HTMLInputElement>eher auf ein FormEvent übertragen.
Oblivionkey3

86

Die korrekte Verwendung in TypeScript ist

  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} />
        ...
    );
  }

Folgen Sie der gesamten Klasse, es ist besser zu verstehen:

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
Hinweis: Um sicherzustellen Arten sind, fügen Sie lib: ["dom"]zu compilerOptionsintsconfig.json
James Conkling

1
@ JamesConkling Vielen Dank!
Alexandre Rivest

1
Und wenn Sie mehrere Eingaben haben, müssen Sie für jede eine Zeile erstellen?
Trevor Wood

Eine andere Möglichkeit, um sicherzustellen, dass 'this' in der handleChange-Funktion ordnungsgemäß zugewiesen ist, besteht darin, handleChange als Pfeilfunktion zu schreiben, dh handleChange = (e: React.ChangeEvent <HTMLInputElement>) => {this.setState (...); }; Auf diese Weise müsste der Konstruktor nicht mehr zum Binden der handleEvent-Funktion verwendet werden.
Tlavarea

Eine weitere Möglichkeit, mit 'this' umzugehen, anstatt die Konstruktor- und Bindemethode zu verwenden, besteht darin, die Pfeilfunktion in der onChange-Prop zu verwenden, dh onChange = {e => this.handleChange (e)}
tlavarea


9

Das, was targetSie hinzufügen wollten, InputPropsist nicht das gleiche, das targetSie wolltenReact.FormEvent

Die Lösung, die ich finden konnte, bestand darin, die ereignisbezogenen Typen zu erweitern, um Ihren Zieltyp hinzuzufügen:

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

Sobald Sie diese Klassen haben, können Sie Ihre Eingabekomponente als verwenden

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

ohne Kompilierungsfehler. Tatsächlich können Sie auch die ersten beiden oben genannten Schnittstellen für Ihre anderen Komponenten verwenden.


Der Werttyp ist kein String!
Roger Gusmao

7

Zum Glück finde ich eine Lösung. du kannst

{ChangeEvent} aus 'reagieren' importieren;

und dann schreibe Code wie: e:ChangeEvent<HTMLInputElement>


2

Hier ist ein Weg mit der ES6-Objektzerstörung, getestet mit TS 3.3.
Dieses Beispiel ist für eine Texteingabe.

name: string = '';

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

1

Dies ist, wenn Sie mit einem FileListObjekt arbeiten:

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
  }

Und stellen Sie sicher, dass Sie "lib": ["dom"]in Ihrem haben tsconfig.


1

Bei Verwendung der untergeordneten Komponente überprüfen wir den Typ wie folgt.

Übergeordnete Komponente:

export default () => {

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

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

Untergeordnete Komponente:

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

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

0

Eine Alternative, die noch nicht erwähnt wurde, besteht darin, die onChange-Funktion anstelle der empfangenen Requisiten einzugeben. Verwenden von React.ChangeEventHandler:

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

-1

Danke @haind

Ja HTMLInputElementhat für das Eingabefeld funktioniert

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

Diese HTMLInputElementSchnittstelle wird HTMLElementgeerbt, von der EventTargetauf Stammebene geerbt wird. Daher können wir mit dem asOperator behaupten, bestimmte Schnittstellen entsprechend dem Kontext zu verwenden, wie in diesem Fall, den wir HTMLInputElementfür Eingabefelder verwenden, andere Schnittstellen usw. sein HTMLButtonElementkönnen HTMLImageElement.

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

Weitere Informationen finden Sie hier

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.