react-reduxにflowtypeを導入しPropsに型を付ける

flowtypeを導入したとき、reactとreduxをつなぐ部分の情報が少なかったのでまとめます。

flowtypeの導入前

比較として導入前のソースを載せておきます。

import React, {PropTypes, Component} from 'react'
import {connect} from 'react-redux'
import * as actions from '../actions

class SamplePage extends Component {
  render() {
    const {title, description, myAction} = this.props

    return (
      <div>
        <button onClick={myAction}>{title}</button>
        <p>{description}</p>
      </div>
    )
  }
}

SamplePage.propTypes = {
  title: PropTypes.string,
  description: PropTypes.string,
  myAction: PropTypes.func
}

const mapStateToProps = state => {
  return {
    title: state.title,
    description: state.description
  }
}

const mapDispatchToProps = dispatch => {
  return {
    myAction: () => dispatch(actions.myAction())
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(SamplePage)

導入後

これが導入後のソースです。propTypesが消えましたが、typeを記述しているので行数はあまり変わっていません。

import React, {Component} from 'react'
import {connect} from 'react-redux'
import * as actions from '../actions
import type {MapStateToProps, MapDispatchToProps} from 'react-redux'

type StateToProps = {
  title: string,
  description: string
}

type DispatchToProps = {
  myAction: () => void
}

type Props = StateToProps & DispatchToProps

class SamplePage extends Component<void, Props, void> {
  render() {
    const {title, description, myAction} = this.props

    return (
      <div>
        <button onClick={myAction}>{title}</button>
        <p>{description}</p>
      </div>
    )
  }
}

const mapStateToProps: MapStateToProps<*, *, StateToProps> = state => {
  return {
    title: state.title,
    description: state.description
  }
}

const mapDispatchToProps: MapDispatchToProps<*, *, DispatchToProps> = dispatch => {
  return {
    myAction: () => dispatch(actions.myAction())
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(SamplePage)

ポイント

propTypesが3つのtypeに置き換えられています。
その中で特に大事なところが以下で、

type Props = StateToProps & DispatchToProps

mapStateToPropsmapDispatchToPropsで生成された2つのオブジェクトのtypeが合成されたものが、

class SamplePage extends Component<void, Props, void> { ...

となりcomponentに渡されていることを明示的に示すことができます。

補足1

MapStateToPropsは以下のように定義されています。

declare type MapStateToProps<S, OP: Object, SP: Object> = (state: S, ownProps: OP) => SP;

ジェネリクスで、SとOPを受け取ってSPを返す関数という型になってますね。
導入後のソースではMapStateToProps<*, *, StateToProps>のように宣言しています。 Stateのtypeを宣言していれば、MapStateToProps<State, *, StateToProps>となり、MapStateToProps内のstateに対して型が適用されるのでSやOPに対しても型の宣言をすることをオススメします。

補足2

2018/02/01現在で最新のflowtypeではComponentに渡すPropsの型を以下のように記述します。

class SamplePage extends Component<Props> { ...