Search code examples
javascriptreactjstypescript

typesafe select onChange event using reactjs and typescript


I have figured out how to tie up an event handler on a SELECT element using an ugly cast of the event to any.

Is it possible to retrieve the value in a type-safe manner without casting to any?

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

Solution

  • Since upgrading my typings to react 0.14.43 (I'm not sure exactly when this was introduced), the React.FormEvent type is now generic and this removes the need for a cast.

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