Vue v3前夜のTypeScript事情をまとめた
May 11, 2020
業務でVue(Nuxt).jsを書きはじめて3ヶ月ほど経った。 それまではReact + TSのプロジェクトだったので、TSの良さは分かっているので、 今のプロジェクトにもTSを導入しようと思っていたが、どうやらVueのTS事情は複雑らしい。 Vueでプロダクトを作る場合、VuexやVue-Routerを使うことが多いが、その中で型の恩恵を受けにくかったり、そもそも書き方が複数あるようだ。 しかもVue3のリリースで、また事情が変わるらしい。
ちょっと時間ができたので、Vue3リリース前のVue + TS事情を調べてまとめておく。 今回はTSを使うためのコードの書き方と、型情報がどのように使用できるかに焦点を当てる。
VueとTypeScriptの今
2020年5月10日現在、Vue v3はベータ版であり、Vue v2.xが最新の公式となる。
この状態でコードの書き方は2通りある。
公式ドキュメントに全てが書いてあるが、
Vue.extend
を使った方法と、 vue-class-component
を使った方法だ。それぞれでかなり書き方が違う。
例えば、こんなVue.jsのcomponentがある場合
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>{{ saySomething() }}</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: {
type: String
},
},
methods: {
saySomething() {
const something = "something";
return something;
},
},
};
</script>
Vue.extend
を使うとこうなり
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>{{ saySomething() }}</p>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "HelloWorld",
props: {
msg: {
type: String
},
},
methods: {
saySomething(): string {
const something = "something";
return something;
},
},
});
</script>
vue-class-component
を使うとこうなる
<template>
<div class="hello">
<h1>{{ messsag }}</h1>
<p>{{ saySomething() }}</p>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class HelloWorld extends Vue {
@Prop() private msg!: string;
saySomething(): string {
const something = "something";
return something;
}
}
</script>
Vue.extend
では、componentの宣言でVueクラスを拡張し、内部の関数などの返り値の型を記述するだけでよいので、通常の書き方に近い。
vue-class-componenはそもそも、Vueの記述をclass-style−syntaxで記述するために用意されているAPIであり、コードの記述が結構変わる。
vue-class-component
はこれからも開発されていくようだが、Vueのv3にそのようなclass-style-syntaxでcomponentを定義するための提案がされていたがhttps://github.com/vuejs/rfcs/pull/17
却下されてしまった。
これを受けて、 Vue.extend
で記述するケースが多くなっているようだ。
また、どちらのパターンでもpropsにTSの型推論を聞かせる
また、Vuexとかmixin使うときには型が自動で解決されないので、手動で型宣言をする必要があるようだ。これについては以下のLINE UITブログがわかりやすかった。
https://engineering.linecorp.com/ja/blog/vue-js-typescript-otoshidama/
Vue v3とTypeScript
前述したcomponentをVue3(Composition API)で書くと、以下のようになる。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>{{ saySomething() }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
props: {
msg: {
type: String
}
},
setup() {
const saySomething = (): string => {
const something = "something";
return something;
};
return {
saySomething
};
}
});
</script>
まあこれはv3でTSを使うための変更というより、単にcompositionAPIを使ってcomponentを定義する書き方の変更のほうが大きい。
composition APIについては公式docsを参照 https://composition-api.vuejs.org/#summary
もしこの書き方でpropsにTSによる型推論を聞かせてsetup内で使いたい場合は
type Props = {
msg: string;
};
みたいな型をつくり
...
setup(props: Props) {
...
こんな感じで型を当てる必要がある。
vuexとかvue-routerはcomposition APIに対応中で、docsはまとまっていなかった・・・w
https://github.com/vuejs/vuex/tree/4.0 https://github.com/vuejs/vue-router-next
気になったらソースコードを見てみよう。
なんなら今のうちにソースコードを追っかけてればdocument自分でかけるかもしれない。
まとめ
以上触れたとおり、
- Vue 2.xではTSの書き方は大きく2種類ある。
- そして、vuexなどを用いるときは型推論が自動できかないので、自分で型を指定する必要がある。
- Vue 3からはcompositionAPIの導入によりさらに書き方が変わる。各ライブラリは鋭意対応中。
って感じ。
あとの詳しいところは実際に使ってみながら調べるかなー。