J'ai compris comment attacher un gestionnaire d'événement sur un élément SELECT en utilisant une distribution laide de l'événement en un.
Est-il possible de récupérer la valeur de manière sécurisée sans transtyper?
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>
);
}
}
Depuis la mise à niveau de mes saisies pour réagir à 0.14.43 (je ne sais pas exactement quand cela a été introduit), le type React.FormEvent est maintenant générique, ce qui supprime la nécessité d'un transtypage.
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>
);
}
}
J'ai essayé d'utiliser React.FormEvent<HTMLSelectElement>
mais cela a entraîné une erreur dans l'éditeur, même s'il n'y a pas de EventTarget
visible dans le code:
La propriété 'valeur' n'existe pas sur la valeur de type 'EventTarget'
Ensuite, j'ai changé React.FormEvent
en React.ChangeEvent
et cela a aidé:
private changeName(event: React.ChangeEvent<HTMLSelectElement>) {
event.preventDefault();
this.props.actions.changeName(event.target.value);
}
Mise à jour: les définitions de types officielles de React incluent les types d'événements en tant que types génériques depuis un certain temps. Vous disposez donc maintenant d'une vérification complète au moment de la compilation et cette réponse est obsolète.
Est-il possible de récupérer la valeur de manière sécurisée sans transtyper?
Oui. Si vous êtes certain de l'élément auquel votre gestionnaire est attaché, vous pouvez faire:
<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'
}
Le compilateur TypeScript autorisera cette assertion de type, car un HTMLSelectElement est un EventTarget. Après cela, il devrait être sûr pour le type, car vous savez que e.target est un HTMLSelectElement, parce que vous venez d'y attacher votre gestionnaire d'événements.
Cependant, pour garantir type-safety (qui, dans ce cas, est pertinent lors du refactoring), il est également nécessaire de vérifier le type d'exécution réel:
if (!(target instanceof HTMLSelectElement))
{
throw new TypeError("Expected a HTMLSelectElement.");
}
Le moyen le plus simple consiste à ajouter un type à la variable qui reçoit la valeur, comme ceci:
var value: string = (event.target as any).value;
Ou vous pouvez convertir la propriété value
ainsi que event.target
comme ceci:
var value = ((event.target as any).value as string);
Modifier:
Enfin, vous pouvez définir ce que EventTarget.value
se trouve dans un fichier .d.ts
séparé. Cependant, le type devra être compatible là où il est utilisé ailleurs, et vous finirez par utiliser any
de toute façon.
globals.d.ts
interface EventTarget {
value: any;
}
Ça marche:
type HtmlEvent = React.ChangeEvent<HTMLSelectElement>
const onChange: React.EventHandler<HtmlEvent> =
(event: HtmlEvent) => {
console.log(event.target.value)
}
Autant que je sache, cela n’est actuellement pas possible - un casting est toujours nécessaire.
Pour que cela soit possible, il faudrait que les fichiers .d.ts de react soient modifiés de sorte que la signature du onChange d’un élément SELECT utilise un nouveau SelectFormEvent. Le nouveau type d'événement exposerait la cible, ce qui expose la valeur. Ensuite, le code pourrait être typesafe.
Sinon, il y aura toujours le besoin d'un casting pour tout.
Je pourrais encapsuler tout cela dans une balise MYSELECT.
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 });
}
En plus de la réponse de @ Thingtrepo:
Jusqu'à ce que nous n'ayons pas clairement défini les événements dans React, il peut être utile de disposer d'une interface cible spéciale pour les contrôles d'entrée:
export interface FormControlEventTarget extends EventTarget{
value: string;
}
Et ensuite, dans votre code transtypé vers ce type, il est approprié d’avoir IntelliSense support:
import {FormControlEventTarget} from "your.helper.library"
(event.target as FormControlEventTarget).value;