32
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

React + Flow で安心して event.target.value を使う

Posted at

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

EventTargetvalueプロパティはないとのこと。
なるほど、これぞ型安全。
事前に問題を発見し、実行時例外を未然に防ぐことができる。
素晴らしい、ありがとう、やっぱり静的型付は最高だぜという話はさておき、それではどうやって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からSyntheticInputEventtargetが追加され、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のエラーを回避する必要がなくなり、分かりやすく簡潔なコードになった。

まとめ

型のある世界で幸せに生きよう。

32
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?