8.3 型安全なVuexモジュール運用


■ 要点まとめ


■ なぜ型安全な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>