Vue.jsは.jsという名前がついている通り、JavaScriptのフレームワークです。最近では、altJS(alternative JavaScript)と呼ばれる、JavaScriptのデメリットを補完する言語の人気が高まっています。その代表的な例がTypeScriptです。本記事ではTypeScriptでVueを扱う方法について実装例も交えながら解説します。
TypeScriptのメリットは?
TypeScriptはaltJSの一つであり、コンパイルすることでJavaScriptに変換されます。JavaScriptにはない静的型付けを行うことでエラーハンドリングが行いやすくなります。また、クラスベースのオブジェクト指向での開発ができることもその特徴です。したがって、TypeScriptを用いることで、Vueをクラス構文で開発しながら実装中にエラーハンドリングをすることができます。
TypeScriptの設定
*Vue-CLIを想定して解説します。Vue-CLIについて詳しく知りたい方は「Vue-CLIのインストール」を参照してください!
Vue-CLI環境でのTypeScriptの設定
Vue-CLIではオプションとしてTypeScriptを用いた環境構築もできます。
$ vue create vuets ? Please pick a preset: default (babel, eslint) ❯ Manually select features
マニュアルを選択します
? Check the features needed for your project: ◉ Babel ❯◉ TypeScript ◯ Progressive Web App (PWA) Support ◯ Router ◯ Vuex ◯ CSS Pre-processors ◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing
オプションとしてTypeScriptを選択しましょう
? Use class-style component syntax? (Y/n) Y
クラス構文で記述するためにclass-style componentを適用します。(クラス構文での書き方については後に説明します)
? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, Linter ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfi lls, transpiling JSX)? Yes ? Pick a linter / formatter config: TSLint ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i > to invert selection)Lint on save ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In packag e.json ? Save this as a preset for future projects? No
その他の設定は以上のような設定で行います。
$ cd vuets $ npm run serve
サーバーを立ち上げて次のような画面になれば準備完了です。
TypeScriptの基本文法
本記事はTypeScriptの書き方について詳しい解説はしませんが、基本的な部分についておさらいしてみます。TypeScriptを使ったことがない方もここさえ押さえれば使っていく中で学習できるでしょう。TypeScriptの変数と関数の宣言についてそれぞれ説明します。
TypeScriptの変数は次のようにして型を指定する必要があります。
(main.ts)
let name: string;
変数を宣言した後に: stringや: numberなどの方法で型を指定することができます。異なる型の値が入った場合はエラーになります。
関数の場合は引数、戻り値に対して型指定ができます。
(main.ts)
function func(name: string): string { return 'hello ' + name }
この場合は引数と戻り値にそれぞれstring型の型指定をしています。戻り値がない場合はvoidとして宣言知ることもできます。
上記の二点のみ知っておけば、今回の記事に出てくるTypeScriptの記法はほとんど網羅しています。
クラス構文によるコンポーネントの書き方・使い方
TypeScriptを導入することで、vue-class-componentにしたがってクラス構文でコンポーネントを記述することができます(コンポーネントの扱いは元のVueと変わりません)。さらに、PropやEmitをvue-property-decoratorにしたがってコンポーネント内に記述することができるため便利です。これらの書き方について本項では説明していきます。今回は次のようなアプリを例にとって説明します。Vueのコンポーネントについて詳しく知りたい方は「VueのComponent(コンポーネント)の書き方・使い方について解説」を参照してください!
ボタンを押した回数の2倍がスコアとなり、50回ボタンを押すとゲームが終了するカウントアプリです。componentsの階層とApp.vueの関係、編集するVueファイルのコードは次のようになっています。
components/ │ ├ AddButton.vue │ └ Display.vue App.vue
(App.vue)
<template> <div> <AddButton @push="countUp"></AddButton> <Display :count="count"></Display> </div> </template> <script lang="ts"> import Component from "vue-class-component"; import { Vue, Watch } from "vue-property-decorator"; import AddButton from "./components/AddButton.vue"; import Display from "./components/Display.vue"; @Component({ components: { AddButton, Display } }) export default class App extends Vue { public count: number = 0; public countUp(): void { this.count++; } @Watch("count", { immediate: true }) public finishCount(newVal: number): void { if (newVal > 50) { alert("ゲーム終了です。"); this.count = 0; } } } </script>
(AddButton.vue)
<template> <div> <button @click="push">click here</button> </div> </template> <script lang="ts"> import Component from "vue-class-component"; import { Emit, Vue } from "vue-property-decorator"; @Component export default class AddButton extends Vue { @Emit("push") public push(): void {}; } </script>
(Display.vue)
<template> <div> <p>you click button {{ count }} times</p> <p>your score : {{doubledCount }} points</p> </div> </template> <script lang="ts"> import Component from "vue-class-component"; import { Prop, Vue } from "vue-property-decorator"; @Component export default class Display extends Vue { @Prop() public count!: number; public get doubledCount(): number { return this.count * 2; } } </script>
コンポーネントをクラスで定義する(@Component)
コンポーネントをエクスポートしたりする際にはクラス形式で定義したコンポーネントの上部に@Componentの記載をします。このような目印のことをアノテーションと呼びます。さらに、クラスがVueのコンポーネントの性質を継承するためにextends Vueの記載を必ず行います。
(AddButton.vue)
@Component export default class AddButton extends Vue { @Emit("push") public push(): void {}; }
また、コンポーネント内部で他のコンポーネントを使用している場合はアノテーションの内部に、使用しているコンポーネントの記載をしなければなりません。
(App.vue)
@Component({ components: { AddButton, Display } })
@Componentは"vue-class-component"のパッケージですが、"vue-property-decorator"からもインポートすることが可能です。
関数やdataの宣言方法
@Componentのアノテーションがついたクラス内部では、data()関数の戻り値として宣言していたdataや、メソッド内で定義していた関数はどちらも、クラスのプロパティのような書き方で扱うことができます。
(App.vue)
public count: number = 0; public countUp(): void { this.count++; }
propsを実装する(@Prop)
propsで親から受け取った変数をクラス内で宣言する際には@Propアノテーションを変数の上部に記載します。
(Display.vue)
@Prop() public count!: number;
この際にpropで受け取る値を必ず設定する必要の有無を!と?を用いることで使い分けることができます。!は必ず設定する必要があるという意味を持っており、今回作成したDisplay.vue内部では、countのpropがなければエラーを発生させます。一方、?は必ず設定している必要はないという意味を持ちます。@Propアノテーションは"vue-property-decorator"からもインポートして利用できます。
propについて詳しく知りたい方は「Vueのpropsの書き方・使い方について解説」を参照してください!
Emitを実装する(@Emit)
emitによって子から親にイベントを送出したい場合は、@Emitアノテーションをハンドラ関数の上部に記載します。
(AddButton.vue)
<button @click="push">click here</button> //省略 @Emit("push") public push(): void {};
@Emitの内部にイベント名を指定することもできます。したがって、親のコンポーネントではpushというカスタムイベントを扱うことができます。@Emitアノテーションは"vue-property-decorator"からもインポートして利用できます。
emitについて詳しく知りたい方は「Component同士でのデータのやり取り」を参照してください!
算出プロパティ(computed)を実装する
算出プロパティはアノテーションではなく、get構文を用いて実装します。
(Display.vue)
public get doubledCount(): number { return this.count * 2; }
算出プロパティについて詳しく知りたい方は「Vueのcomputedプロパティの書き方・使い方について解説」を参照してください!
監視(watchプロパティ)を実装する(@Watch)
watchプロパティを扱う際には@Watchアノテーションを用います。
(App.vue)
@Watch("count", { immediate: true }) public finishCount(newVal: number): void { if (newVal > 50) { alert("ゲーム終了です。"); this.count = 0; } }
@Watch内に監視する変数やimmediate、deepなどのオプションについての記述ができます。watchプロパティについて詳しく知りたい方は「Vueのwatchプロパティの書き方・使い方について解説」を参照してください!
この記事のまとめ
本記事ではVueをTypeScriptで記述する方法を、実際の実装例を元に説明しました!最後に記事の要点をまとめてみましょう。
- Vue-CLIのオプションでTypeScriptを開発環境に加えることができる
- TypeScriptでは静的型付けによる変数や関数の宣言ができる
- "vue-class-component"や"vue-property-decorator"を用いて、@によるアノテーションを活用したクラス構文でコンポーネントを書くことができる
Vue.tsを是非活用してみましょう。