こちらの記事で紹介したように、Vue CLI 3からVue.jsを手軽にTypeScriptで書くことができるようになりました。しかし、vuexに関してはそのままではTypeScriptで書くのは難しいように思います。
そこで、今回は vuex-module-decorators というサードパーティ製のパッケージを使って、より安全でスマートにvuexを扱う方法を紹介します。
以下のコマンドでパッケージをインストールします。
// for npm npm install -D vuex-module-decorators // for yarn yarn add -D vuex-module-decorators
TypeScriptを使用する場合は tsconfig.json に以下の設定をします。
vuex-module-decorators での記述を見る前に、通常の vuex での記述を見てみましょう。一般的には以下のような記述になると思います。
import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) const counter = { state: { count: 0 }, mutations: { increment (state) { state.count++ } }, getters: { twice (state) { return state.count * 2 } } } const store = new Vuex.Store({ state: {}, modules: { counter } })
これを TypeScript と vuex-module-decorators を使って記述すると以下のようになります。
import Vue from "vue" import Vuex from "vuex" import { Module, VuexModule, Mutation } from "vuex-module-decorators" Vue.use(Vuex) @Module class Counter extends VuexModule { count: number = 0 @Mutation increment() { this.count++ } get twice():number { return this.count * 2 } } const store = new Vuex.Store({ state: {}, modules: { Counter } })
vuex 標準の記述と比べて見やすくなったのではないでしょうか。それでは個別に見てみましょう。
state はクラスのプロパティとして定義します。
@Module class Counter extends VuexModule { count: number = 0
mutation は @Mutation で定義します。 なお、@Mutation を使うためには、事前に Mutation をimportする必要があります。
import { Module, VuexModule, Mutation } from "vuex-module-decorators" @Module class Counter extends VuexModule { @Mutation increment() { this.count++ } }
action は @Action で定義します。 なお、@Action を使うためには、事前に Action をimportする必要があります。
import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators" @Module class Counter extends VuexModule { count: number = 0 @Mutation add(val: number) { this.count += val } @Action({ commit: "add" }) add5() { return } }
getter はアクセサーとして定義します。
@Module class Counter extends VuexModule { count: number = 0 get twice():number { return this.count * 2 } }
@MutationAction を使うと複数の state を一度に commit することができます。return はJSON形式で指定します。なお、@MutationAction を使うためには、事前に MutationAction をimportする必要があります。
import { Module, VuexModule, MutationAction } from "vuex-module-decorators" @Module class Counter extends VuexModule { count1: number = 0 count2: number = 0 @MutationAction({ mutate: ["count1", "count2"] }) async setAll() { return { count1: 10, count2: 20 } } }
動的にモジュールを登録するには以下のようにします。
import Vue from "vue" import Vuex from "vuex" import { Module, VuexModule, Mutation } from "vuex-module-decorators" Vue.use(Vuex) const store = new Vuex.Store({}) @Module({ dynamic: true, store: store, name: "counter" }) class Counter extends VuexModule { count: number = 0 @Mutation increment() { this.count++ } }
最後に、 vuex-module-decorators を使ったサンプルコードを紹介します。
import { Module, VuexModule, Mutation, Action, getModule } from "vuex-module-decorators" import store from "@/store/store" export interface ICounterState { count: number } @Module({ dynamic: true, store: store, name: "counter", namespace: true }) class Counter extends VuexModule { count: number = 0 @Mutation increment() { this.count++ } @Mutation add(val: number) { this.count += val } @Action({ commit: "add" }) add5() { return 5 } get twice():number { return this.count * 2 } } export const counterModule = getModule(Counter)
import Vue from "vue" import Vuex from "vuex" import { ICounterState } from "./modules/counter" Vue.use(Vuex) export interface IRootState { counter: ICounterState } export default new Vuex.Store<IRootState>({})
<template></template> <script lang="ts"> import { Component, Vue } from "vue-property-decorator" import { counterModule } from "@/store/modules/counter" @Component export default class Home extends Vue { get count(): number { return counterModule.count } get twice(): number { return counterModule.twice } increment() { counterModule.increment() } addCount(val: number) { counterModule.add(val) } add5() { counterModule.add5() } } </script>
vuex-module-decorators と TypeScript で vuex をスマートに扱う方法を紹介しました。 vuex-module-decorators のGitHubにも様々なサンプルが用意されているので、一度見てみると理解が深まると思います。