こんにちは。エンジニアの小椋です。
最近になって初めてTypeScriptを使う機会があり、TypeScriptもっと使おう!😠😠😠と思ったので、今回はVue.jsでTypeScriptを使う方法を紹介したいと思います!
TypeScriptを使ったVue.jsプロジェクトの始め方
vue-cli 3.0からはvue create
の時に対話形式でTypeScriptを使うかどうかを選択することができるようになりました。
今回はそれを使って初めからTypeScript標準搭載のプロジェクトを作ります。
vue create vue-ts
すると
? Please pick a preset
と聞かれるので、Manually select features
を選びます。
ラジオボタンが出てくるので、スペースキーで◉TypeScript
にチェックを入れ、エンターキーで確定します。
今回は◉Router
もプリセットで追加しておきました。
ここで◉TypeScript
にチェックが入っていると、
? Use class-style component syntax? (Y/n)
と聞かれます。
後で解説するクラス記法を使用するかどうかの質問なのですが、とりあえずY
にします。
(class-style component syntaxを使用する場合、vue-class-component
モジュールが追加で必要になります。Y
を選択すると、プリセットの生成時に自動でインストールされます。)
残りの質問も全部Y
にしておきましょう。
これでTypeScriptでVueを書く準備は完了です!👏👏👏
.
├── README.md
├── babel.config.js
├── node_modules
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── src
├── tsconfig.json
└── tslint.json
ルートディレクトリにtsconfig.json
、tslint.json
などTypeScript関連のファイルが生成されているのが確認できます。
開発サーバーを起動しておきましょう。TypeScriptでも、当然ホットリロード 機能が利用できます!
npm run serve
TypeScriptじゃないHelloWorldとちょっと中身が違いますね。
TypeScriptを使った.vueファイルの書き方
Vue.jsを使ったことがある人は、src/components/HelloWorld.vue
などを見ると、よく知っている.vue
ファイルと若干様子が違うことが分かると思います。
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class HelloWorld extends Vue {
@Prop() private msg!: string;
}
</script>
script
タグ部分にlang="ts"
と指定がある
lang="ts"
を書き忘れると、そのvueファイルでTypeScriptの記法は使えません。コンパイルエラーになります。
- Vueオブジェクトを
extends
したclassベースの記法になっている
こちらが今回の本題です。
Vue.jsでは今までオブジェクト形式でdata
やmethods
などを全て定義して、Vueインスタンスをnew
する特有な書き方に馴染みがあると思います。
TypeScriptではそれとは違い、よりTypeScript FriendlyなClass Style Vue Component記法を利用することができます。
Class Style Vue Component
ここからは、Class Style Vue Component(以下クラス記法)の書き方を紹介します。
vue-routerをプリセットで選択した時に入っているsrc/views/About.vue
ファイルを編集していきます。
コンポーネントの作成
通常vueファイルで、Vueコンポーネントを作成する場合、
<script>
export default {
name: 'About',
}
</script>
このように書きますが、クラス記法の場合は以下のように書きます。
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {}
</script>
@Component
は、vue-property-decorator
という公式サポートのライブラリを利用して、直下で宣言されているクラスがVueコンポーネントであることを示すアノテーションです。
dataの定義
ここからはコンポーネントのプロパティの書き方です。
早速ですが、Vue.jsのdata
プロパティの定義、まわりくどいですよね?
初めて触った時data
プロパティはfunction
にしろって言われて???ってなりましたよね?
<script>
export default {
name: 'About',
data() {
return {
id: 0,
}
}
}
</script>
でもクラス記法なら単なるクラスのメンバ変数として書けるので、スッキリです!👏👏👏
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {
id: number = 0
}
</script>
methodsの定義
いつものmethods
<script>
export default {
methods: {
myMethod(id) {
// 処理
}
}
}
</script>
クラス記法ではメンバ関数として書けます。
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {
myMethod(id: number): void {
// 処理
}
}
</script>
computedの定義
いつものcomputed
<script>
export default {
computed: {
myCalc() {
// 処理
}
}
}
</script>
クラス記法ではgetter
とsetter
として書くことでcomputed
プロパティを表すことができます。
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {
get myCalc(): number {
// 処理
}
set myCalc(): void {
// 処理
}
}
</script>
ライフサイクルフックの定義
JavaScriptの場合
<script>
export default {
created() {
// 処理
},
mouted() {
// 処理
},
destroyed() {
// 処理
},
// ...
}
</script>
クラス記法では特定の名前のクラスメンバメソッドとして書くことでライフサイクルフックを定義できます。
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {
created(): void {
// 処理
}
mounted(): void {
// 処理
}
destroyed(): void {
// 処理
}
// ...
}
</script>
props、emit、watchなどの定義
クラス記法では、これらはvue-property-decorator
でアノテーションとしてサポートされています。
<script lang="ts">
import { Component, Prop, Emit, Watch, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {
@Prop() myProp!: string // !は必須です
@Emit('my-event') // 発火させるイベント名を文字列で指定
myEvent(v: string): void {}
emitMyEvent() {
this.myEvent('hello')
}
@Watch('myProp') // 監視するメンバを文字列で指定
onChangeMyProp(val: string, old: string): string {
// 処理
}
}
</script>
なんか@Emit
はちょっとくどい感じしますね。ちなみにクラス記法でもthis.$emit('my-event', 'hello')
は使えます。
@Componentについて
@Component
に引数を渡すと、new Vue()
するときと同じような挙動になります。
つまり、
@Component({
props: ['one', 'two'],
data() { return { hoge: 'hoge' } },
methods: {
piyo: function (v) {
this.$emit('piyo-event', 'piyopiyo')
}
}
})
export default class HelloWorld extends Vue {}
みたいなことができます。
何に使うんだ、、、って感じですが、filters
とかアノテーションが用意されていないプロパティは@Component
に渡すことで実装できます。
(クラスと離れたところに書かなきゃいけないので多少可読性が落ちますね・・・)
まとめ
Vue.jsでTypeScriptを使うメリット
これは一般的にTypeScriptを使うメリットとほとんど同じです。
あとメリットとしては、個人的にはクラス記法は可読性が高いと思うので好みです。TypeScript慣れしている人やオブジェクト指向言語の開発に馴染みのある人ならなおさらそうだと思います。
でも既存のVueプロジェクトに追加でTypeScriptを導入する場合なんかは、通常の記法で静的型付けを行うのがいいのではないでしょうか。
// これも書ける(lang="ts"必須)
export default {
methods: {
foo(v: string): void {
console.log(v)
}
}
}
書き方をほぼ変えずにTypeScriptのメリットも享受できるので、Vue.jsの記法に慣れている人にはとても分かりやすいですね!👍
まだVSCodeの拡張機能(Vetur)でのコードスニペットがうまくいかなかったりする部分はありますが、行く行くはVue.js + TypeScriptでの開発環境がもっと整って一般的になることを個人的には期待しています!👏👏👏👏👏