Ich habe herausgefunden, wie man einen Ereignishandler an ein SELECT-Element bindet, indem ich eine hässliche Besetzung des Ereignisses mit einem beliebigen Element verwende.
Ist es möglich, den Wert typsicher abzurufen, ohne ihn zu übertragen?
import React = require('react');
interface ITestState {
selectedValue: string;
}
export class Test extends React.Component<{}, ITestState> {
constructor() {
super();
this.state = { selectedValue: "A" };
}
change(event: React.FormEvent) {
console.log("Test.change");
console.log(event.target); // in chrome => <select class="form-control" id="searchType" data-reactid=".0.0.0.0.3.1">...</select>
// Use cast to any works but is not type safe
var unsafeSearchTypeValue = ((event.target) as any).value;
console.log(unsafeSearchTypeValue); // in chrome => B
this.setState({
selectedValue: unsafeSearchTypeValue
});
}
render() {
return (
<div>
<label htmlFor="searchType">Safe</label>
<select className="form-control" id="searchType" onChange={ e => this.change(e) } value={ this.state.selectedValue }>
<option value="A">A</option>
<option value="B">B</option>
</select>
<h1>{this.state.selectedValue}</h1>
</div>
);
}
}
javascript
reactjs
typescript
davestevens
quelle
quelle
Antworten:
Ich habe versucht, zu verwenden,
React.FormEvent<HTMLSelectElement>
aber es führte zu einem Fehler im Editor, obwohlEventTarget
im Code nichts sichtbar ist:Dann wechselte ich
React.FormEvent
zuReact.ChangeEvent
und es half:private changeName(event: React.ChangeEvent<HTMLSelectElement>) { event.preventDefault(); this.props.actions.changeName(event.target.value); }
quelle
Seit dem Upgrade meiner Eingaben auf die Reaktion 0.14.43 (ich bin mir nicht sicher, wann dies genau eingeführt wurde) ist der Typ React.FormEvent jetzt generisch und macht eine Besetzung überflüssig.
import React = require('react'); interface ITestState { selectedValue: string; } export class Test extends React.Component<{}, ITestState> { constructor() { super(); this.state = { selectedValue: "A" }; } change(event: React.FormEvent<HTMLSelectElement>) { // No longer need to cast to any - hooray for react! var safeSearchTypeValue: string = event.currentTarget.value; console.log(safeSearchTypeValue); // in chrome => B this.setState({ selectedValue: safeSearchTypeValue }); } render() { return ( <div> <label htmlFor="searchType">Safe</label> <select className="form-control" id="searchType" onChange={ e => this.change(e) } value={ this.state.selectedValue }> <option value="A">A</option> <option value="B">B</option> </select> <h1>{this.state.selectedValue}</h1> </div> ); } }
quelle
event.currentTarget.value
, um die Daten aus dem Formular zu erhalten.Update: Die offiziellen Typdefinitionen für React enthalten seit einiger Zeit Ereignistypen als generische Typen, sodass Sie jetzt die vollständige Überprüfung der Kompilierungszeit durchführen können und diese Antwort veraltet ist.
Ja. Wenn Sie sich über das Element sicher sind, an das Ihr Handler angehängt ist, können Sie Folgendes tun:
<select onChange={ e => this.selectChangeHandler(e) }> ... </select>
private selectChangeHandler(e: React.FormEvent) { var target = e.target as HTMLSelectElement; var intval: number = target.value; // Error: 'string' not assignable to 'number' }
Live-Demo
Der TypeScript-Compiler lässt diese Typzusicherung zu , da ein HTMLSelectElement ein EventTarget ist . Danach sollte es typsicher sein, da Sie wissen, dass e.target ein HTMLSelectElement ist , weil Sie gerade Ihren Ereignishandler daran angehängt haben.
Um jedoch die Typensicherheit zu gewährleisten (die in diesem Fall beim Refactoring relevant ist), muss auch der tatsächliche Laufzeittyp überprüft werden:
if (!(target instanceof HTMLSelectElement)) { throw new TypeError("Expected a HTMLSelectElement."); }
quelle
e.target
eine istHTMLSelectElement
, ist diese Typzusicherung sicher , und alle nachfolgenden Typprüfungen sind von Natur aus sicher, ztarget.value
. Wenn Sie es absolut kugelsicher machen möchten, können Sie auch eine Laufzeitprüfung für seinen Typ durchführen und einTypeError
if auslösen, dase.target
nicht vom richtigen Typ ist. Dies wird eigentlich nie passieren, aber es fügt eine zusätzliche Schicht garantierter Typensicherheit hinzu.onChange
Stütze.Am einfachsten ist es, der Variablen, die den Wert empfängt, einen Typ hinzuzufügen:
var value: string = (event.target as any).value;
Oder Sie könnten die
value
Immobilie genauso wieevent.target
folgt besetzen:var value = ((event.target as any).value as string);
Bearbeiten:
Zuletzt können Sie definieren, was
EventTarget.value
sich in einer separaten.d.ts
Datei befindet. Der Typ muss jedoch dort kompatibel sein, wo er an anderer Stelle verwendet wird, und Sie werden ihnany
ohnehin wieder verwenden.globals.d.ts
interface EventTarget { value: any; }
quelle
EventTarget.value
besteht darin, das globale eventTarget zu erweitern, was über eine beliebige .ts-Datei erfolgen kann:declare global { interface EventTarget { value: any; }}
Es klappt:
type HtmlEvent = React.ChangeEvent<HTMLSelectElement> const onChange: React.EventHandler<HtmlEvent> = (event: HtmlEvent) => { console.log(event.target.value) }
quelle
In meinem Fall wurde das onChange-Ereignis als React.ChangeEvent eingegeben:
onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => { console.warn('onChange TextInput value: ' + e.target.value); } }
quelle
JSX :
<select value={ this.state.foo } onChange={this.handleFooChange}> <option value="A">A</option> <option value="B">B</option> </select>
TypeScript :
private handleFooChange = (event: React.FormEvent<HTMLSelectElement>) => { const element = event.target as HTMLSelectElement; this.setState({ foo: element.value }); }
quelle
Soweit ich das beurteilen kann, ist dies derzeit nicht möglich - eine Besetzung ist immer erforderlich.
Um dies zu ermöglichen, müssten die .d.ts von react so geändert werden, dass die Signatur von onChange eines SELECT-Elements ein neues SelectFormEvent verwendet. Der neue Ereignistyp würde das Ziel verfügbar machen, wodurch der Wert verfügbar gemacht wird. Dann könnte der Code typsicher sein.
Andernfalls ist immer eine Besetzung erforderlich.
Ich könnte das alles in einem MYSELECT-Tag zusammenfassen.
quelle
Zusätzlich zu der Antwort von @oughtrepo:
Bis wir in React keine definitiv eingegebenen Ereignisse haben, kann es nützlich sein, eine spezielle Zielschnittstelle für Eingabesteuerelemente zu haben:
export interface FormControlEventTarget extends EventTarget{ value: string; }
Und dann in Ihrem Code, der in diesen Typ umgewandelt wurde, wo IntelliSense- Unterstützung angebracht ist:
import {FormControlEventTarget} from "your.helper.library" (event.target as FormControlEventTarget).value;
quelle