29
17

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.

Flowtype+reduxにおけるreducerの正しい型付け

Last updated at Posted at 2017-09-16

よく以下のような型付けを見ます。

// @flow
import { Actions, type Action } from './actions'

export type State = {
  count: number,
  other: string,
}

const initialState: State = { count: 0, other: 'test' }

export default function(state: State = initialState, action: Action): State {
  switch (action.type) {
    case Actions.INCREMENT:
      return { ...state, counter: state.count + 1 }
    default:
      return state
  }
}

一見正しいように見えます。
flowの型エラーはでません。
しかし、よく見ると、countcounterとタイポしています。
これでは型安全などと言えませんね。

$Shape<T>を使った改善

この型のオブジェクトは、Tに記述されていないプロパティを含むことはできません。

type T = {
  foo: string,
  bar: number
}
const a: $Shape<T> = {
  foo: '121', // no errors about not having bar 
  baz: true   // error, baz is not in T type
}

これをreducerで使うと以下のようになります。
reducerの戻り値の型を$Shape<State>に変更します。

スクリーンショット 2017-09-16 17.18.05.png

グレート!
定義されてないcounterで型エラーが起きました。
countに直しましょう。

スクリーンショット 2017-09-16 17.19.55.png

エラーが消えました。
しかし、残念ながら、これではダメです。
定義したStateの型は以下でした。

type State = {
  count: number,
  other: string,
}

プロパティotherが消えているのに検知出来ていません。

T & $Shape<T> を使う

これを解決するには以下の型を定義します。

type Exact<T> = T & $Shape<T>

これは、Tのプロパティ全てかつそれ以外のプロパティを許容しない型です。

するとプロパティが足りない場合正しくflowが検知します。

スクリーンショット 2017-09-16 17.26.35.png

...stateを追加しましょう。
これで、reducerが型で守られるようになりました。

スクリーンショット 2017-09-16 17.54.36.png

全体では、以下のようになります。もちろんExactはreducerごとに定義するのではなくimport typeした方がよいでしょう。

スクリーンショット 2017-09-16 18.08.03.png

なぜ$Exact<T>ではダメなのか?

$Exact<T>だと全てのオブジェクトが正しくないとダメなので、{...state}を使うとその時点でエラーが起きてしまいます。
なので{ ...state, count: state.count + 1 }で型エラーが発生してしまいます。

スクリーンショット 2017-09-16 18.17.35.png

追記

{| |}$Exact<T>と同等です。

おわりに

上記のスクリーンショットのエディタはAtom-IDEを使っています。

Exact<T>ですが、それぞれのreducerに毎回import typeするか悩みますね。
どこでも使えるようにグローバルに定義してしまってもいいかもしれないとも思っています。
何かあればコメント欄またはtwitterにて議論しましょう。

関連記事

Flowtypeのactionの型付け。String Literal型とString型について
http://qiita.com/akameco/items/e7021e22da4c9e14463a

29
17
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
29
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?