redux-actions よりも TypeScript FSA の方が良さそう

React+Redux+TypeScriptの環境で、Action関連のコーディングを効率化するライブラリーを検討してみました。

前提

TypeScript

Flux Standard Action

「Flux Standard Action」(FSA)とは、Actionオブジェクトの形式を規定したもので、Reduxの事実上の標準となっています。

インターフェースとして書くと、以下のようになります:

{
  type: string;
  payload?: any;
  error?: boolean;
  meta?: any;
}

Action関連のコーディングを効率化するライブラリーは、FSAをサポートしています。

また、Reduxでは Action Creator や Reducer の実装がパターン化していて、決まりきったコードを書いていく必要がありますが、こういったライブラリーを使うと、よりシンプルなコードで記述することが可能になります。

redux-actions

この種のライブラリーで最も有名なのは、redux-actions でしょう。

redux-actions でのコードは以下のようになります:

// Action
const { increment, decrement } = createActions({
  'INCREMENT': amount => ({ amount: 1 }),
  'DECREMENT': amount => ({ amount: -1 })
});

//Reducer
const reducer = handleActions({
  [increment](state, { payload: { amount } }) {
    return { counter: state.counter + amount }
  },
  [decrement](state, { payload: { amount } }) {
    return { counter: state.counter + amount }
  }
}, defaultState);

Reducer の処理が各Actionで同じなので、まとめることもできるのですが、イメージしやすいように、Actionごとの記述方法にしました。

TypeScript FSA

TypeScript FSA も redux-actions と同様の機能を提供するライブラリーで、さらに TypeScript に対応しています。

ただし、TypeScript FSA はAction側しかサポートしていません。

Reducer側は、TypeScript FSA Reducers という別ライブラリーになっています。

TypeScript FSA でのコードは以下のようになります:

// Action
const actionCreator = actionCreatorFactory();
export const increment = actionCreator<{amount: number}>('INCREMENT');
export const decrement = actionCreator<{amount: number}>('DECREMENT');

//Reducer
const reducer = reducerWithInitialState(defaultState)
  .case(increment, (action, amount) => ({ ...state, counter: state.counter + amount }))
  .case(decrement, (action, amount) => ({ ...state, counter: state.counter + amount }));

上の redux-actions の処理と同じことを実現しています。

TypeScript FSA をお勧めする理由

コードを比較すると、両者とも大きな違いはありませんが(好みは別として)、実は TypeScript では redux-actions のコードはエラーになります(この記事を書いている時点では)。

原因は createActions()@types/redux-actions で定義されていないためです。

バージョンを確認してみると、

  • redux-actions@2.2.1
  • @types/redux-actions@1.2.6

@types/redux-actions が結構古いですね。

ということで、型定義が一緒になっている TypeScript FSA をお勧めします。

 

なお、他のライブラリーでも @types のバージョンが大きく遅れているものがありますね。

TypeScript でやっていくと、こういうところで悩まされるのかあ。

ちょっと不安を感じてしまいました。