flow-typeの導入

前回React.jsの理解を深めるために楽天トラベル空室検索APIを使ったホテル検索アプリケーションを自作しました。
axiosを使って非同期通信をしたり、初めてMaterial-UIを導入してみたり、理解を深める最初の一歩には良かった題材だったと思います。
そして第二弾としてTwitter APIを利用したTwitterクライアントを作成中です！前回できなかったことを盛り込んだ練習をしようと思い、その一つにFlow Typeを入れました。（Twitterクライアントに関するスキルセット等はまた後日。）


参考にしたサイトの中で、

- [FLOW Redux](https://flow.org/en/docs/react/redux/)（公式サイト）
- [Flow: Type Checking with Flow in React + Redux](https://www.robinwieruch.de/the-soundcloud-client-in-react-redux-flow/)
- [react-reduxにflowtypeを導入しPropsに型を付ける](https://akaimo.hatenablog.jp/entry/2018/02/01/233105)

が大変役立ちました！

チュートリアルはこちらですね。

- [Testting React Apps](https://jestjs.io/docs/en/tutorial-react.html#content)

Youtubeもありますので、導入にはオススメです！

- [Youtbe: React Flow Tutorial ( Static Type Checking Props, State and set Default Props )](https://www.youtube.com/watch?v=L0nJTyHBTtE)


##【Flowを導入する手順】

####①ライブラリインストール
Flowtypeに必要なライブラリをインストールします。
（私は以下をインストールしましたが、お好みでインストールを。

```text
$ yarn add -D @babel/preset-flow eslint-plugin-flowtype flow-bin
```

####②webpack.config.jsに追記

webpack.config.jsに`@babel/preset-flow`を追加しました。

```javascript
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env',
                '@babel/preset-react',
                '@babel/preset-flow', //追加
              ],
            },
          },
          {
            loader: 'eslint-loader',
          },
        ],
  以下省略
}
```

####③.flowconfigファイルを作成

.flowconfigファイルを新規作成して、以下のような記述をしました。

```text
[ignore]
.*/node_modules/.*
.*/dist/.*

[include]

[libs]
flow-typed

[lints]

[options]
module.name_mapper='^@app\(.*\)$' -> '<PROJECT_ROOT>/src/js/\1'

[strict]
```

####④ソースコードに`// @flow`を頭につけて、型宣言開始！

ソースコードの一番上に`// @flow`を書いて、初めていきましょう！

---

これから実際に変更したソースコードをご紹介していきます。
複雑なことはあまりしていません。


##【変更したソースコード】

###コンポーネント


![1.png](https://qiita-image-store.s3.amazonaws.com/0/327745/1c0c26c5-b3cd-8350-7832-70c9aa12b7d7.png)



`prop-types`を使っていましたが、propTypesで記述していた箇所は全削除しましょう！

以下の記述の通り、`mapStateToProps`で渡ってくるデータを`StateProps`、`mapDispatchToProps`で渡す関数を`DispatchProps`で型宣言しています。
authは外部APIを使用してるので`any`にしました。
その下にコンポーネント内で使う`this.state`を`State`で型宣言しています。

```javascript
type StateProps = {
  auth: any,
}
type DispatchProps = {
  authTwitter: () => Promise<Object>,
  twitterSignOut: () => Promise<Object>,
  getUserAccount: () => Promise<Object>,
}
type Props = StateProps & DispatchProps

type State = {
  dialogOpen: boolean,
}

class TwitterAuth extends React.Component<Props, State> {
  state = {
    dialogOpen: false,
  }

  static defaultProps = {
    authTwitter: () => {},
    twitterSignOut: () => {},
    getUserAccount: () => {},
  }
  以下省略
}

const mapStateToProps: Object = (state: StateProps) => ({
  auth: state.auth,
})
export default withRouter(
  connect(
    mapStateToProps,
    { authTwitter, twitterSignOut, getUserAccount }
  )(TwitterAuth)
)
```

また、イベント系は引数を`event: SyntheticEvent<*>`に変えました。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/327745/01a078dc-db61-4744-9d5b-3fee18dce8b3.png)


```javascript
handleChange = (event: SyntheticInputEvent<HTMLInputElement>) => {
  省略
}
handlePostTweet = (event: SyntheticEvent<*>) => {
  省略
}
```


###Reducer

![3.png](https://qiita-image-store.s3.amazonaws.com/0/327745/7e824884-8c37-d5a4-1afc-e21260ea4bdf.png)


Reducerは複雑なことはしていません。
引数のstateとactionの型を宣言したのと、帰ってくる値を`: Object`で追加してあげました。

```javascript
export default (state: Object = INITIAL_STATE, action: Object): Object => {
  switch (action.type) {
    case GET_TIMELINE_REQUEST:
      return {
        省略
```

###Action

Actionの記述は以下のようにしています。

![4.png](https://qiita-image-store.s3.amazonaws.com/0/327745/343091f2-322e-e39c-e828-1aace23558d5.png)


見るとお分かりかと思いますが、Flow公式サイトの通りに実装しています。

Typing Redux reducers
https://flow.org/en/docs/react/redux/#toc-typing-redux-reducers

```javascript
type State = Object
type Action =
  | { type: AUTH_TWITTER_REQUEST }
  | { type: AUTH_TWITTER_SUCCESS, payload: State }
  | { type: AUTH_TWITTER_ERROR, error: Object }
  | { type: USER_SIGN_IN, payload: Object }
  | { type: USER_SIGN_OUT }

type Dispatch = (action: Action | ThunkAction | PromiseAction) => any
type GetState = () => State
type ThunkAction = (dispatch: Dispatch, getState: GetState) => any
type PromiseAction = Promise<Action>

export const authTwitter = (): ThunkAction => async dispatch => {
  ...
}
```

今のところファイル分割しているActionコンポーネント全てに上記の記述をしてますので、もしかしたらまとめられるのかもです。


##【触れてみた感想】
運用中のアプリケーションやブログ、公式サイト見てきましたが、書き方は人によってそれぞれだと思いました！
使用しているライブラリのバージョンが新しすぎるとFlowtypeが対応してなかったりします。（実は記事ではあげてませんが、まだエラーが残っていたりします。。）
回避方法をググりまくっていますので、エラー出てしまっている箇所は解決次第追記していきます。


##【最後に】
まだ私が触ったのはFlowtypeの基本のキだと思います。
実際に運用されている案件の型宣言を見ると、まだ「なんだこれは…！」と思ってしまいます^_^;
個人的にTypescriptを習得したい…！その前にテストについて調べねば。そしてそしてReact.js関連（Next.jsとかGatsbyとか）も習得したいです。
下の記事が参考になりましたので、さらに理解を深めてまいります。

[2018 年 React と Redux のエコシステム総まとめ](https://qiita.com/kotarella1110/items/e76bf9cca665157f3d2e)