Vue Typescript の書き方 (Decoratorあり、なし)

## Vue で Typescript 使う意義

一般的に型定義をもっとも使いたい箇所は インターフェイス部分だと思います。
Vue でいうと Props にあたります。
Props には動的型チェックがついており、定義しておくと動作時に型チェックをしてくれます。

ただこの機能は動かなさないと型チェックができません。
またVue Props はオブジェクトや配列など中身までチェックする複雑なデータの型チェックがあまり得意ありません。

（個人的にはもともと Vue についている動的チェックで十分ではないかと思ったりします。）

ただ Typescript の書き方がいくつかあり、[Vue の公式ドキュメントの Typscript の項目](https://jp.vuejs.org/v2/guide/typescript.html)はあまり情報量がないので、Qiita にも書いてみます。（他に結構書いてるかたいることにあとで気づいた・・）

## Vue Typescript で Decorator を使う使わないの選択

## Decorator 使わないパターン

こちらは JS とほとんど変わらない作りになっています。
props の型チェックは、vue の Runtime のみになります。


```vue
<template>
    <div>
        <div class="greeting">Hello {{name}}{{exclamationMarks}}</div>
        <button @click="decrement">-</button>
        <button @click="increment">+</button>
    </div>
</template>

<script lang="ts">
import Vue from "vue";

export default Vue.extend({
    props: {name: {type:String, defalut:"" }, 
            initialEnthusiasm: {type:Number, defalut:0 }
           },
    data() {
        return {
            enthusiasm: this.initialEnthusiasm,
        }
    },
    methods: {
        increment() { this.enthusiasm++; },
        decrement() {
            if (this.enthusiasm > 1) {
                this.enthusiasm--;
            }
        },
    },
    computed: {
        exclamationMarks(): string {
            return Array(this.enthusiasm + 1).join('!');
        }
    }
});
</script>
```

[こちら](https://github.com/microsoft/TypeScript-Vue-Starter/blob/master/src/components/HelloDecorator.vue)を参考にしました。

### Decorator を使うパターン

```vuejs
<template>
  <div>
    <input v-model="msg">
    <p>prop: {{propMessage}}</p>
    <p>msg: {{msg}}</p>
    <p>helloMsg: {{helloMsg}}</p>
    <p>computed msg: {{computedMsg}}</p>
    <button @click="greet">Greet</button>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class App extends Vue {
  // 型は TypeScript コンパイル字にチェック、デフォルト値を設定
　// Props 変更することはないので readonly を指定
  @Prop({ default: '' }) readonly propMessage: String

  //data の定義
  msg = 123
  helloMsg = 'Hello, ' + this.propMessage

  // lifecycle の定義
  mounted () {
    this.greet()
  }

  // computed の定義
  get computedMsg () {
    return 'computed ' + this.msg
  }

  // method の定義
  greet () {
    alert('greeting: ' + this.msg)
  }
}
</script>
```

[こちら](https://github.com/vuejs/vue-class-component)を参考にしました。


## どっちが良い？
ケースバイケースだと思います。

### Decoratorを使わないパターンが良いケース
- Decorator を学習している時間がない時や、これから Vue を使い始めるエンジニアが多い場合 Docorator を使うとコード見た目が結構違うので公式ドキュメントからは学びづらいと思います。


### Decoratorを使うパターンの方が良いケース
- Vue の Props には形チェックがついてますが、動かさないとチェックできません。
- Object や Array の中身までチェックしたい時は、Typescript の方がやりやすいと思います。



### どっちを使う？

2019年時点では 公式のドキュメントが薄いので、フロントエンドをバリバリやっているメンバー以外に使ってくださいと展開するには参考情報が少なく、新規プロジェクトのようなお手本となるコードが少ないケースでは、自分だったら Decorator がないパターンを採用すると思います。

最終的には合う合わないで決めるのが良いと思います。

時間やメンバーのスキルに余裕があるならせっかく TSを導入するなら、Decorator を使ってみても良いとかな(?)とも思います。

[追記]
自分は当初 Decorator を使わないと props の型が付けれないと思っていたのですが、
[こちら](https://qiita.com/iMasanari/items/31d8a26c7ee22793585c#array%E3%81%A8object%E3%81%AB%E3%82%82%E5%9E%8B%E3%81%AE%E6%8C%87%E5%AE%9A%E3%82%92)の記事をみてそうでもないとわかったので、Vue.extend で十分な気がしています。

## 有益な情報源

参考に掲載した下記のサイトは TypeScript を使う上で道標となると思います。
おおよそのパターンの把握はできると思います。

- https://github.com/vuejs/vue-class-component
- https://github.com/kaorun343/vue-property-decorator
- https://github.com/microsoft/TypeScript-Vue-Starter