2015-10-21 5 views
23

Я выяснил, как связать обработчик события с элементом SELECT с помощью уродливого приведения события к любому.typeafe select onChange event using reactjs и машинописный текст

Возможно ли получить значение в безопасном типе без литья в какой-либо?

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

что это значит типизированного? –

+0

Я предполагаю, что это означает, что скомпилировано с помощью машинописного текста и проверяет, что все присваивания переменных полностью соответствуют их типу. Мы говорим о машинописных текстах, конечно, не javascript –

ответ

27

С обновлением моих типизаций в отредактируйте 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> 
     ); 
    } 
} 
+9

По состоянию на декабрь 2016 года необходимо использовать 'event.currentTarget.value' , чтобы получить данные из формы. –

+1

Дэйв, подумайте об обновлении вашего примера. – Alex

+1

@MartinMajewski Я отредактировал для использования currentTarget (http://joequery.me/code/event-target-vs-event-currenttarget-30-seconds/ - это хорошее объяснение) – davestevens

9

Самый простой способ добавить тип в переменную, который принимает значение, например:

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

Или вы могли бы бросить value собственности, а также event.target вроде этого:

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

Edit:

И последнее, что вы можете определить, что EventTarget.value находится в отдельном файле .d.ts. Тем не менее, тип должен быть совместим там, где он используется в другом месте, и вы в конечном итоге снова используете any.

globals.d.ts

interface EventTarget { 
    value: any; 
} 
+0

Я надеялся полностью избавиться от «как любой». – davestevens

+0

Хорошо, обновил ответ – thoughtrepo

+0

Спасибо за ваши мысли, но это еще не отвечает на мой вопрос. Я думаю, что ответ заключается в том, что .d.ts реакции нужно будет изменить так, чтобы сигнатура onChange элемента SELECT использовала новый SelectFormEvent. В противном случае, когда вы укажете, ему нужен бросок. Думаю, я мог бы инкапсулировать это в тег MYSELECT. – davestevens

3

Насколько я могу сказать, что это в настоящее время не представляется возможным - литая всегда требуется.

Чтобы сделать возможным, необходимо отредактировать .d.ts реакции, чтобы сигнатура onChange элемента SELECT использовала новый SelectFormEvent. Новый тип события будет раскрывать цель, которая выдает значение. Тогда код может быть видовым.

В противном случае всегда будет необходимость в отливке.

Я мог бы инкапсулировать все это в теге MYSELECT.

0

В дополнение к @ thoughtrepo отвечают:

Пока мы не определенно набрали события в React это может быть полезно иметь специальный целевой интерфейс для управления вводом:

export interface FormControlEventTarget extends EventTarget{ 
    value: string; 
} 

, а затем в вашей код приведен к этому типу, где это целесообразно иметь INTELLISENSE поддержки:

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

(event.target as FormControlEventTarget).value; 
7

Возможно ли получить значение в безопасном типе без каста?

Да. Если вы уверены в элементе обработчик прикреплен, вы можете сделать:

<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

машинописи компилятор позволит этого типа на утверждение, так как HTMLSelectElement является EventTarget. После этого он должен быть безопасным по типу, потому что вы знаете, что e.target - это HTMLSelectElement, потому что вы просто привязали к нему свой обработчик событий.

Однако для гарантии типа безопасности (который в данном случае имеет значение, когда рефакторинг), он также необходим для проверки фактического выполнения типа:

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

Я полагаю, что это лучше, чем кастинг для любого, но вы все еще используете утверждение типа, и этого я и старался избежать. – davestevens

+0

Да, но поскольку вы полностью уверены, что 'e.target' является' HTMLSelectElement', этот тип-утверждение является _safe_, и все последующие проверки типов также являются неотъемлемо безопасными, например 'target.value'. Если вы хотите сделать его абсолютно пуленепробиваемым, вы также можете выполнить проверку времени выполнения для своего типа и бросить 'TypeError', если' e.target' не соответствует типу. Это никогда не произойдет, но добавляет дополнительный уровень безопасности _guaranteed_. –

+0

http: // stackoverflow.com/questions/260626/what-is-type-safe, что я понимаю по типам, заключается в том, что проверка типов накладывается компилятором. Это означает, что нет утверждений типа и не зависит от исключений во время выполнения. – davestevens

6

Я попытался с помощью React.FormEvent<HTMLSelectElement>, но это привело к ошибке в редакторе, событие, хотя нет EventTarget видно в коде:

Свойство «значение» не существует на значение типа 'EventTarget'

Тогда я изменил React.FormEvent к React.ChangeEvent и это помогло:

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

это работает:

type HtmlEvent = React.ChangeEvent<HTMLSelectElement> 

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