概要
React(Redux)のコードをTypeScriptで書いています。TypeScriptは静的型チェックができるので、とても重宝しています。
さて、ReactとReduxを結びつけるReact-Reduxのconnect関数
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) - reduxjs/react-redux
の引数
mapStateToProps(state, [ownProps]): stateProps
ですが、このステート(state)の型は何を指定していますか?
ここにはReduxのストアで管理される全ステートが格納されたオブジェクトが渡されますが、この型をTypeScript(2.8以降)でサクッと解決する方法を紹介したいと思います。
使用するストア
例として、書籍のランキングと購入書籍ジャンルのステートをストアで管理しているとします。
書籍ジャンルを選ぶと、そのジャンルに属する書籍の人気ランキングが表示されるようなデータをイメージしています。
export interface IBook {
isbn: string;
name: string;
author: string;
publisher: string;
categoryId: string;
}
export interface ICategory {
id: string;
name: string;
}
export interface IRankingState {
category: ICategory;
ranking: IBook[];
}
export interface ICategoryState {
categories: ICategory[];
}
import { IRankingState, INavState } from './states';
export const ranking = (state = initialStateRanking, action: RankingActions): IRankingState => {
~略~
}
export const shopping = (state = initialStateNav, action: NavActions): INavState => {
~略~
}
import { createStore, combineReducers } from 'redux';
import * as reducers from './reducers';
const reducer = combineReducers({ ...reducers });
export const store = createStore(reducer);
ストアが管理するステートは以下のようになります。
この例では2つしかステートがありませんが、実際のアプリケーションではこの数倍(数十倍)の数になると思います。
{
ranking: IRankingState;
shopping: INavState;
}
stateの型の記述方法
1. anyで回避(ダメな例1)
const mapStateToProps = (state: any) => ({
...state.ranking
});
anyを指定するとコンパイルエラーは回避できますが、TypeScriptの利点である静的型チェックが使えなくなってしまいますね。
2. 全ステートをマージしたAllState型を準備する(ダメな例2)
type RankingState = {
ranking: IRankingState;
}
type NavState = {
shopping: INavState;
}
type AllState = RankingState & NavState;
const mapStateToProps = (state: AllState) => ({
...state.ranking
});
ステートが2~3個程度ならまだ我慢できますが、ステートが増えるたびにメンテするのは面倒ですね。
これだったらanyで逃げる方がよいのではないかと思えてきます。
3. ReturnTypeで型解決
import { store } from './store';
type AllState = ReturnType<typeof store.getState>;
const mapStateToProps = (state: AllState) => ({
...state.ranking
});
ストア(store)のgetState関数の戻り型を、TypeScript2.8以降で実装されたReturnTypeで取得しています。
これがまさにストアが管理する全ステートを内包した型になります。
ストア管理のステートが増えたとしても、この方法であれば特別な対処は不要になります。