vue-property-decoratorを用いてVueXにTypeScript導入


まずは今回用いる
<dl>
  <dt>VueX</dt>
  <dt>TypeScript</dt>
</dl>

について簡単に説明します。

##VueX

状態管理します。
Global変数のことを指していると自分は理解しています。

どのcomponent
からもこのvuexで管理されている

<dl>
  <dt>値</dt>
  <dt>メソッド</dt>
</dl>

にアクセスできるようになります。


##TypeScript


スーパーJSと自分は理解しています。

javascriptにできることは全てtypescriptで対応できます。

typescriptは画面で用いられる際はjavascriptにコンパイル（変換）
されて利用できるようになります。




##vue-property-decoratorとは？？

自分が新規の案件でvueを用いて開発しようとしたときに用いることになったツールになります。
ツールという表現が正しいかは置いておきます。

現在VueXにも型安全を取り込もうとTs
を導入した場合

VueX内では簡単に用いさせてくれませんでした。
シンプルいVueとTsはあ仕様が悪いです。


Vue.3.0を待ちましょう。。。。

なので

vue-property-decorator

をこの度は用いました。


少しVueの書き方とは異なるclassを用いた書き方のためてこずってしまいましたが慣れてきたので今回紹介させていただきます。



##導入

Vue Cli使ってください。

https://qiita.com/nunulk/items/7e20d6741637c3416dcd

この記事を参考に

tsとVueXを用いる部分を参考にしてみてください。


```
npm install -S vue-class-component
npm install -S vue-property-decorator
```

でdownloadです。


src/store/planディレクトリを作り
planでぃレクトリ配下に

plan.ts
types.ts

をそれぞれ作ります。

```
plan
 |
 |--plan.ts
 |--types.ts
```

イメージはこんな形です。


##plan.ts

plan.tsの中身は本来VueXで定義している中身を記述します。

```plan.ts

import {
  Module,
  VuexModule,
  Mutation,
  Action,
  getModule,
} from 'vuex-module-decorators';
import store from '../store';
import { Plan, PlanDetail, setPlan } from './types';

@Module({ dynamic: true, store, name: 'PlanModule', namespaced: true })
class PlanModule extends VuexModule {
  public plan: Plan[] = [];

  //planのgetterメソッド
  public get getPlans(): object {
    return this.plan;
  }

  @Mutation
  public setPlan(payload: setPlan) {
    console.log(payload);
    this.plan[payload.planId] = payload.payLoad;
  }

  @Action
  public addPlan(payload: object): void {
    let planCount = Object.keys(this.plan).length;
    console.log(planCount + 1, payload);
    this.setPlan({ planId: planCount + 1, payLoad: payload });
  }
}

export default getModule(PlanModule);

```

```
@Module({ dynamic: true, store, name: 'PlanModule', namespaced: true })
```

おまじないみたいなものなので覚えましょう。詳細は調べてみてください。

###state

VueX内では
stateで定義されていたVueX内のパラメータは

```plan.ts
  public plan: Plan[] = [];
```

に変わっています。
このPlan型はまた記述しますが型を持ったinterfaceになります。

なのでこのplan変数の中にグローバルで用いたい値が入ってきます。


###getter

getterメソッドもまたVuexとは異なり

```plan.ts
  //planのgetterメソッド
  public get getPlans(): object {
    return this.plan;
  }

```

このような形でgetを頭につけてメソッド名を定義してあげます。
でts導入しているので型を宣言してあげます。

慣れてきたでしょうか？

###Mutation

```plan.ts
  @Mutation
  public deletePlan(planId: number) {
    this.plan.splice(planId, 1);
  }
//stateのplanを変更する処理のみを行うメソッドになります。
//変更する値は基本的にactionから渡してもらいます。
```

@Mutationを記述するだけで簡単にmutationの中身をかけます。

vuexのMutationの説明になりますが



+ 基本的にstateを変更するメソッドのみ
+ 複雑ななロジックは書かない
+ stateを唯一変更することができるメソッドをかける

そういったメソッドを持っています。

なのでもし状態を管理するstateを変更したい場合は
必ずこのmutationを経由する必要があります。



##Action

```plan.ts
  @Action
  public addPlan(payload: object): void {
    let planCount = Object.keys(this.plan).length;
    this.setPlan({ planId: planCount + 1, payLoad: payload });
  }
//Actionの記述になります。
```

こちらもMutation同様に＠Actionを記述するだけとなります。

+ componentから受け取った処理を記述する。
+ 非同期処理を行う
＋ state変更は行はない


が特徴のメソッドになります。
state変更は行えますが、行わないというルールがありますので従います。
Actionで変更できるようにしてしまうと、どこが原因でエラーが起きているかなどが追いづらくなります。
stateの変更は決して行わないことに注意です。


##外部で読み込み可能に

```
export default getModule(PlanModule);
```

この記述を最後に入れておかないと他のComponentで
読み込むことができなくなりますので注意です。

では先ほど作成したModuleを外部から用いていきましょう！


##Componentから用いる


```PlanListComponent.vue

//PlanListComponent.vueというPlanをlistにしたComponentになります。

<template>
  <div>
    <v-content v-for="(plan, index) in plans" :key="index">
      <v-hover v-slot:default="{ hover }">
        <v-card
          :elevation="hover ? 14 : 2"
          class="mx-auto pa-3"
          max-width="344"
          outlined
        >
          <v-card-title>
            {{ plan.planTitle }}
          </v-card-title>
          <v-card-text>
            {{ plan.issueContent }}
          </v-card-text>
          <v-container fluid fill-height>
            <v-row class="d-flex align-center justify-space-around">
              <v-btn>編集</v-btn>
              <v-btn @click="planDelete(index)">削除</v-btn>
            </v-row>
          </v-container>
        </v-card>
      </v-hover>
    </v-content>
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import PlanModule from '../../store/plan/plan';

@Component
export default class PlanListModule extends Vue {
  public plans: object = {};

  created() {
    this.plans = this.getPlans;
  }

  protected get getPlans() {
    return PlanModule.getPlans;
  }

  planDelete(planId: number) {
    PlanModule.deletePlan(planId);
    this.plans = this.getPlans;
  }
}
</script>

```

上記のようなファイルを作ってみました。


肝になってくるのは

```js
import PlanModule from '../../store/plan/plan';
```

で先ほど作成した

```js
export default getModule(PlanModule);
```
Moduleをimportしてくる箇所です。
importさえしてしまえば

```
  protected get getPlans() {
    return PlanModule.getPlans;
  }

  planDelete(planId: number) {
    PlanModule.deletePlan(planId);
    this.plans = this.getPlans;
  }
```

Module名.Moduleで定義したメソッド名で

そのModuleのメソッドが使えてしまいます！
これでVueX内も役割ごとに大きく分割できます。