Javascript typesafe 使用 reactjs 和 typescript 选择 onChange 事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33256274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 14:51:24  来源:igfitidea点击:

typesafe select onChange event using reactjs and typescript

javascriptreactjstypescript

提问by davestevens

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

我已经想出了如何使用一个丑陋的事件转换到 any 来绑定一个 SELECT 元素上的事件处理程序。

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

采纳答案by davestevens

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.

由于将我的类型升级为 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>
        );
    }
}

回答by Sergei Basharov

I tried using React.FormEvent<HTMLSelectElement>but it led to an error in the editor, even though there is no EventTargetvisible in the code:

我尝试使用React.FormEvent<HTMLSelectElement>但它导致编辑器中出现错误,即使EventTarget代码中没有可见:

The property 'value' does not exist on value of type 'EventTarget'

“EventTarget”类型的值上不存在属性“value”

Then I changed React.FormEventto React.ChangeEventand it helped:

然后,我改变React.FormEventReact.ChangeEvent它帮助:

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

回答by John Weisz

Update: the official type-definitions for React have been including event types as generic types for some time now, so you now have full compile-time checking, and this answer is obsolete.

更新:React 的官方类型定义已经包含事件类型作为泛型类型已有一段时间了,所以你现在有完整的编译时检查,这个答案已经过时了。



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

是否可以以类型安全的方式检索值而不强制转换为任何值?

Yes.If you are certain about the element your handler is attached to, you can do:

是的。如果您确定处理程序附加到的元素,则可以执行以下操作:

<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

现场演示

The TypeScript compiler will allow this type-assertion, because an HTMLSelectElementis an EventTarget. After that, it should be type-safe, because you know that e.targetis an HTMLSelectElement, because you just attached your event handler to it.

TypeScript 编译器将允许这种类型断言,因为HTMLSelectElement是一个EventTarget。之后,它应该是类型安全的,因为您知道e.target是一个HTMLSelectElement,因为您刚刚将事件处理程序附加到它。

However, to guaranteetype-safety (which, in this case, is relevant when refactoring), it is also needed to check the actual runtime-type:

然而,为了保证类型安全(在这种情况下,在重构时是相关的),还需要检查实际的运行时类型:

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

回答by thoughtrepo

The easiest way is to add a type to the variable that is receiving the value, like this:

最简单的方法是向接收值的变量添加一个类型,如下所示:

var value: string = (event.target as any).value;

Or you could cast the valueproperty as well as event.targetlike this:

或者你可以像这样投射value属性event.target

var value = ((event.target as any).value as string);

Edit:

编辑:

Lastly, you can define what EventTarget.valueis in a separate .d.tsfile. However, the type will have to be compatible where it's used elsewhere, and you'll just end up using anyagain anyway.

最后,您可以定义EventTarget.value单独.d.ts文件中的内容。但是,该类型必须与在其他地方使用的地方兼容,any无论如何您最终都会再次使用。

globals.d.ts

globals.d.ts

interface EventTarget {
    value: any;
}

回答by Петр Графинов

it works:

有用:

type HtmlEvent = React.ChangeEvent<HTMLSelectElement>

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

回答by Hymankobec

In my case onChange event was typed as React.ChangeEvent:

在我的例子中,onChange 事件被输入为 React.ChangeEvent:

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

回答by Marco Lackovic

JSX:

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

回答by davestevens

As far as I can tell, this is currently not possible - a cast is always needed.

据我所知,目前这是不可能的 - 总是需要演员阵容。

To make it possible, the .d.ts of react would need to be modified so that the signature of the onChange of a SELECT element used a new SelectFormEvent. The new event type would expose target, which exposes value. Then the code could be typesafe.

为了使其成为可能,需要修改 react 的 .d.ts,以便 SELECT 元素的 onChange 签名使用新的 SelectFormEvent。新的事件类型将公开目标,从而公开值。然后代码可以是类型安全的。

Otherwise there will always be the need for a cast to any.

否则总是需要演员阵容。

I could encapsulate all that in a MYSELECT tag.

我可以将所有这些都封装在一个 MYSELECT 标签中。

回答by Artru

In addition to @thoughtrepo's answer:

除了@thoughtrepo 的回答:

Until we do not have definitely typed events in React it might be useful to have a special target interface for input controls:

除非我们在 React 中没有明确键入的事件,否则为输入控件提供一个特殊的目标接口可能会很有用:

export interface FormControlEventTarget extends EventTarget{
    value: string;
}

And then in your code cast to this type where is appropriate to have IntelliSensesupport:

然后在您的代码中转换为这种类型的适合具有 IntelliSense支持的位置:

 import {FormControlEventTarget} from "your.helper.library"

 (event.target as FormControlEventTarget).value;