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 でやっていくと、こういうところで悩まされるのかあ。
ちょっと不安を感じてしまいました。