javascript - filterableproducttable - react select example
Mecanografíe el evento OnChange de Typeafe usando reactjs y mecanografíe (7)
He descubierto cómo atar un controlador de eventos en un elemento SELECT usando un reparto feo del evento a cualquiera.
¿Es posible recuperar el valor de una manera segura para el tipo sin lanzarlo a ninguno?
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>
);
}
}
Además de la respuesta de @ thoughtrepo:
Hasta que no tengamos eventos escritos en React, puede ser útil tener una interfaz de destino especial para los controles de entrada:
export interface FormControlEventTarget extends EventTarget{
value: string;
}
Y luego, en su código convertido a este tipo, es apropiado tener soporte de IntelliSense :
import {FormControlEventTarget} from "your.helper.library"
(event.target as FormControlEventTarget).value;
Desde que actualicé mis mecanografías para reaccionar 0.14.43 (no estoy seguro exactamente de cuándo se introdujo), el tipo React.FormEvent ahora es genérico y esto elimina la necesidad de un lanzamiento.
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>
);
}
}
Intenté usar React.FormEvent<HTMLSelectElement>
pero dio lugar a un error en el editor, aunque no hay EventTarget
visible en el código:
La propiedad ''valor'' no existe en el valor del tipo ''EventTarget''
Luego cambié React.FormEvent
a React.ChangeEvent
y me ayudó:
private changeName(event: React.ChangeEvent<HTMLSelectElement>) {
event.preventDefault();
this.props.actions.changeName(event.target.value);
}
La forma más fácil es agregar un tipo a la variable que está recibiendo el valor, como esto:
var value: string = (event.target as any).value;
O puedes lanzar la propiedad value
así como event.target
esta manera:
var value = ((event.target as any).value as string);
Editar:
Por último, puede definir qué EventTarget.value
está en un archivo .d.ts
separado. Sin embargo, el tipo tendrá que ser compatible cuando se usa en otros lugares, y de todos modos acabarás usando any
nuevo.
globals.d.ts
interface EventTarget {
value: any;
}
Por lo que puedo decir, esto no es posible actualmente, siempre se necesita un yeso.
Para hacerlo posible, los .d.ts de reaccion deberían modificarse para que la firma del onChange de un elemento SELECT use un nuevo SelectFormEvent. El nuevo tipo de evento expondría el objetivo, lo que expone el valor. Entonces el código podría ser tipográfico.
De lo contrario, siempre habrá la necesidad de un elenco para cualquiera.
Podría encapsular todo eso en una etiqueta MYSELECT.
funciona:
type HtmlEvent = React.ChangeEvent<HTMLSelectElement>
const onChange: React.EventHandler<HtmlEvent> =
(event: HtmlEvent) => {
console.log(event.target.value)
}
Actualización: las definiciones de tipo oficiales para React han incluido tipos de eventos como tipos genéricos desde hace algún tiempo, por lo que ahora tiene una verificación completa de tiempo de compilación, y esta respuesta está obsoleta.
¿Es posible recuperar el valor de una manera segura para el tipo sin lanzarlo a ninguno?
Sí. Si está seguro del elemento al que está conectado su controlador, puede hacer:
<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''
}
El compilador de TypeScript permitirá esta aseveración de tipo, porque un HTMLSelectElement es un EventTarget . Después de eso, debería ser de tipo seguro, porque sabes que e.target es un elemento de selección de HTML , porque simplemente le adjuntaste el controlador de eventos.
Sin embargo, para garantizar la seguridad de tipo (que, en este caso, es relevante al refactorizar), también es necesario verificar el tipo de tiempo de ejecución real:
if (!(target instanceof HTMLSelectElement))
{
throw new TypeError("Expected a HTMLSelectElement.");
}