TL;DR
onChange
の引数にEvent
ではなくSyntheticInputEvent
を使う
https://github.com/facebook/flow/issues/218
これまでのやり方
たとえばこんな、テキストを入力して反映するだけのコンポーネント。
/* @flow */
import React from 'react'
class InputField extends React.Component {
state: { text: string }
constructor(props) {
super(props)
this.state = { text: '' }
}
handleChange(e : Event) {
const text = e.target.value // error!
this.setState({text})
}
render() {
return (
<input type="text" value={this.state.text} onChange={this.handleChange} />
)
}
}
React.render(
<InputField />,
document.body
)
これは許されない。
14: const text = e.target.value
^ property `value`. Property not found in
14: const text = e.target.value
^ EventTarget
EventTarget
にvalue
プロパティはないとのこと。
なるほど、これぞ型安全。
事前に問題を発見し、実行時例外を未然に防ぐことができる。
素晴らしい、ありがとう、やっぱり静的型付は最高だぜという話はさておき、それではどうやってvalue
にアクセスするのか。
例:愚直にHTMLInputElementであることを確認する
handleChange(e : Event) {
const target = e.target;
if (target instanceof HTMLInputElement) {
this.setState({text: target.value}})
}
}
例:自前でEventの型を用意する
declare type ElementEventTemplate<E> = {
target: E
} & Event
declare type InputEvent = ElementEventTemplate<HTMLInputElement>
....
handleChange(e : InputEvent) {
const text = e.target.value
this.setState({text}})
}
例:いっそHTMLInputElementにキャストする
handleChange(e : Event) {
const text = ((e.target: any):HTMLInputElement).value
this.setState({text}})
}
痛々しくて見てられないので以下略。
これからのやり方
このEvent.target.value
についてはかなり前から議論されていたようで、v0.35からSyntheticInputEvent
にtarget
が追加され、HTMLInputElement
を参照できるようになった。
https://github.com/facebook/flow/commit/167b126b81ead513274678e4895f769525d6decb
HTMLInputElement
にはvalue
が定義されているので、これで何の問題もなくSyntheticInputEvent.target
からvalue
へ直接アクセスできるようになる。
handleChange(e : SyntheticInputEvent) {
const text = e.target.value // No error!
this.setState({text})
}
条件分岐したり、キャストしたり、小技を噛ませてflowのエラーを回避する必要がなくなり、分かりやすく簡潔なコードになった。
まとめ
型のある世界で幸せに生きよう。