commit
, dispatch
を作る(Vuex × TypeScript 完全型安全設計)commit
や dispatch
の第一引数(名前)と第二引数(payload)の対応を型で縛るcommitTyped
, dispatchTyped
みたいなラッパー関数を作ると実現できる「3番のラーメン2つください!」
→ メニュー番号間違ってたら店員に怒られる。
→ 個数を間違っても怒られる。
→ 番号と内容がセットで正しいかどうかチェック。
それが型付き
commit
/dispatch
。
types.ts
)// RootState
export interface RootState {
count: number;
userName: string;
}
// Mutation types
export const MutationTypes = {
Increment: 'increment',
SetUserName: 'setUserName'
} as const;
export type MutationType = typeof MutationTypes[keyof typeof MutationTypes];
// Action types
export const ActionTypes = {
UpdateUserName: 'updateUserName'
} as const;
export type ActionType = typeof ActionTypes[keyof typeof ActionTypes];
// mutation payloads
export interface MutationPayloads {
[MutationTypes.Increment]: undefined;
[MutationTypes.SetUserName]: string;
}
// action payloads
export interface ActionPayloads {
[ActionTypes.UpdateUserName]: string;
}
// action returns
export interface ActionReturns {
[ActionTypes.UpdateUserName]: boolean;
}
commitTyped
の作成// 型付き commit 関数
import { Store } from 'vuex';
import { RootState, MutationType, MutationPayloads } from './types';
export const commitTyped = <
T extends MutationType
>(
store: Store<RootState>,
type: T,
payload: MutationPayloads[T]
): void => {
store.commit(type, payload);
};
dispatchTyped
の作成// 型付き dispatch 関数
import { ActionType, ActionPayloads, ActionReturns } from './types';
export const dispatchTyped = async <
T extends ActionType
>(
store: Store<RootState>,
type: T,
payload: ActionPayloads[T]
): Promise<ActionReturns[T]> => {
return await store.dispatch(type, payload);
};