Vue.js + Vuex + TypeScript を試行錯誤してみた

この1週間、Vue + Vuex + TypeScript の書き方を模索していた。
これといったデファクトはないっぽくて、結構大変かもという感想。

Anonyfox/vuex-store-module-example

色々ググった中で、まずは Vuex の Issue にあったやり方を試した。

state, getter, mutation, action の世界で型をつけるには良いけど、Component にマッピングするとき、ゆるふわで少し残念かも。
ここの繋がりがもう少し堅いと、コードベースが大きくなったときにリファクタリングしやすかったり、色々と便利そう。

src/store/modules/counter.ts

src/components/Counter/index.ts

@Component<Counter>({
    methods: {
        ...mapActions(['incc', 'dec']) // incc のように typo しても教えてくれない(教えてほしい)
    }
})
export default class Counter extends Vue {
    // ... 略 ...
}

ktsn/vuex-type-helper

次に Vuex メンテナである ktsn さんが作成されたライブラリを試した。
コミット履歴をみると、ちょうど僕が模索を始めた頃に作られたみたいで、運が良かった。

state, getter, mutation, action の interface を用意して、Vuex.createNamespacedHelpers から mapper をつくると、Component にマッピングするときも堅くできる。

src/store/modules/jiro.ts

src/components/Jiro/index.ts

@Component<Jiro>({
    methods: {
        ...app.mapActions(['name']),
        ...jiro.mapActions(['prev', 'nextt']) // nextt なんてものはないと教えてくれる
    }
})
export default class Jiro extends Vue {
    name: (payload: {name: string}) => void; // けど悩みはあり、ここに型は書きたくない
    // name: (a: any) => any; // このような適当な書き方も許される

    created() {
        this.name({name: 'Jiro'});
    }
}

上記の this.name() のように使う場合は、どのように定義を書けば DRY なのだろう。
もっと良い書き方はありそう。

それと vue template から使うときにも間違いの検知ができると嬉しい。
でも、なんとなく難しそう。

Example

まるっとしたソースコードはこちら。 github.com

実行は以下とおり。

git clone https://github.com/utahta/vue-vuex-typescript-example.git
cd vue-vuex-typescript-example
make
make open