8.3 型安全なVuexモジュール運用
■ 要点まとめ
- Vuexモジュールを型安全(Type-Safe)に管理する
- ActionやMutationの引数、戻り値まで型で縛る
- 型定義ファイル(interface)を活用して補完とチェックを強化する
- storeへのアクセス時も明示的な型付けを行う
■ なぜ型安全なVuex運用が重要なのか?
理由 |
説明 |
ミスを早期に検知できる |
IDEやTypeScriptがすぐにエラーを教えてくれる |
リファクタリングが安全にできる |
型が崩れないので安心して書き換えできる |
自動補完が効く |
開発効率が劇的に上がる |
大規模チーム開発で威力を発揮 |
誤ったパラメータや呼び出し方を防げる |
■ ✅ 型定義ファイルを分離する(例)
// ファイル名: src/types/store.ts
// ルート情報
export interface RouteInfo {
name: string;
path: string;
}
// sampleModuleのState
export interface SampleModuleState {
text: string;
currentRoute: RouteInfo;
}
// Getter
export interface SampleModuleGetters {
textLength: number;
currentRouteName: string;
}
// Mutation Payload
export interface SetTextPayload {
newText: string;
}
export interface SetCurrentRoutePayload {
route: RouteInfo;
}
// Action Payload
export interface UpdateTextPayload {
newText: string;
}
export interface UpdateRoutePayload {
route: any;
}
■ ✅ Vuexモジュールに型を適用する
// ファイル名: src/store/modules/sampleModule.ts
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
import { RouteInfo } from '@/types/store';
@Module({ namespaced: true, name: 'sampleModule' })
export default class SampleModule extends VuexModule {
// 型をつけて明示
public text: string = '初期テキスト';
public currentRoute: RouteInfo = { name: '', path: '' };
// Getter
get textLength(): number {
return this.text.length;
}
get currentRouteName(): string {
return this.currentRoute.name;
}
// Mutation
@Mutation
setText(newText: string) {
this.text = newText;
}
@Mutation
setCurrentRoute(route: RouteInfo) {
this.currentRoute = route;
}
// Action
@Action
async updateText(newText: string) {
this.context.commit('setText', newText);
}
@Action
updateRoute(route: any) {
const routeInfo: RouteInfo = {
name: route.name || '',
path: route.path || '',
};
this.context.commit('setCurrentRoute', routeInfo);
}
}
■ ✅ コンポーネント側でも型を使う
// ファイル名: src/components/ParentComponent.vue
<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
import { SampleModuleState } from '@/types/store';
// useStore()が使えない場合は↓
// store.getters['sampleModule/textLength']みたいに明示呼び出しする
const textLength = computed<number>(() => store.getters['sampleModule/textLength']);
const currentRouteName = computed<string>(() => store.getters['sampleModule/currentRouteName']);
// アクション呼び出し時も型を明示
async function updateTextAction(newText: string): Promise<void> {
await store.dispatch('sampleModule/updateText', newText);
}
</script>