جاوااسکریپت - رویداد onChange انتخاب ایمن با نوع با استفاده از ReactJS و TypeScript


من فهمیدهام چگونه میتوان یک هندلر رویداد را روی یک عنصر SELECT با استفاده از یک تبدیل ناپسند از رویداد به any متصل کرد.

آیا امکان بازیابی مقدار به صورت نوعامن بدون استفاده از تبدیل به 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>
        );
    }
}

پاسخ شماره ۱

من سعی کردم از React.FormEvent<HTMLSelectElement> استفاده کنم اما این باعث یک خطا در ویرایشگر شد، حتی با اینکه هیچ EventTarget در کد دیده نمیشود:

خصوصیت 'value' روی مقدار از نوع 'EventTarget' وجود ندارد

سپس من React.FormEvent را به React.ChangeEvent تغییر دادم و این مفید بود:

private changeName(event: React.ChangeEvent<HTMLSelectElement>) {
    event.preventDefault();
    this.props.actions.changeName(event.target.value);
}

پاسخ شماره ۲

از زمانی که تایپهای خود را به react 0.14.43 ارتقا دادم (مطمئن نیستم دقیقاً چه زمانی این معرفی شد)، نوع React.FormEvent اکنون عمومی است و این نیاز به تبدیل را از بین میبرد.

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

پاسخ شماره ۳

در مورد من، رویداد onChange به صورت React.ChangeEvent<HTMLSelectElement> تایپ شده بود:

onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
  console.warn('onChange TextInput value: ' + e.target.value);
}}

پاسخ شماره ۴

بهروزرسانی: تعاریف نوع رسمی برای React مدتی است که نوعهای رویداد را بهعنوان نوعهای عمومی شامل میشوند، بنابراین اکنون بررسی کامل زمان کامپایل را دارید و این پاسخ منسوخ شده است.


آیا امکان بازیابی مقدار به صورت نوعامن بدون استفاده از تبدیل به any وجود دارد؟

بله. اگر از عنصری که هندلر شما به آن متصل است مطمئن هستید، میتوانید این کار را انجام دهید:

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

نمایش زنده

کامپایلر TypeScript اجازه این تایپاثری را میدهد، زیرا یک HTMLSelectElement یک EventTarget است. پس از آن، باید ایمن از نظر نوع باشد، زیرا شما میدانید که e.target یک HTMLSelectElement است، زیرا شما همینالان هندلر رویداد خود را به آن متصل کردهاید.

با این حال، برای تضمین ایمنی نوع (که در این مورد، هنگام بازسازی کد مرتبط است)، همچنین لازم است نوع واقعی هنگام اجرای برنامه بررسی شود:

if (!(target instanceof HTMLSelectElement))
{
    throw new TypeError("Expected a HTMLSelectElement.");
}

پاسخ شماره ۵

کار میکند:

type HtmlEvent = React.ChangeEvent<HTMLSelectElement>

const onChange: React.EventHandler<HtmlEvent> = 
   (event: HtmlEvent) => { 
       console.log(event.target.value) 
   }