TechVue.jsJapanese

TypeScript コンポーネント を Vue3 プロジェクト に追加

Tech

こちらの記事で TypeScript を有効にした プロジェクト を作成しました。 今回は Vue3 プロジェクト に TypeScript コンポーネント を追加して 実際に Vue.js のなかで TypeScript を使っていきたいと思います。

macOS: 12.1
vue: 3.2.1
typeScript: 4.5.5

Vue3 における TypeScript コンポーネント 必須要素

[ads]

TypeScript の コンポーネント とはいえ Vue.js の中では 素の JavaScript 同様に 拡張子 を vue として コンポーネント を作成していく形になります。 本記事では src / components ディレクトリ に TypeScriptSample.vue という ファイル を作成していきます。

vue ファイル に含める要素は JavaScript 同様に以下です。

  • template タグ
  • script タグ
  • style タグ

JavaScript では template -> script -> style の順番で記載することが多かった印象ですが、 TypeScript では script -> template -> style と HelloWorld.vue 記載されています。 本 ブログ でもその形式で進めたいと思います。

なお スタイルガイド によると style タグ が最後であれば template と script の順番はどちらが先でもよく プロジェクト 内で一貫していれば良さそうです。

JavaScript と異なる点としては 以下の2点が挙げられます。

  1. script タグ に lang=”ts” を指定
  2. script タグ 内で defineComponent() を記載

それでは 少し詳細をみていきます。

script タグ に lang=”ts” を指定

“To use TypeScript in SFCs, add the lang=”ts” attribute to <script> tags. ”

Vue.js
Vue.js - The Progressive JavaScript Framework

script タグ では 公式 サイト に記載されている通り以下のように記載します。

<script lang="ts"></script>

script タグ 内で defineComponent() を記載

To let TypeScript properly infer types inside component options, we need to define components with defineComponent():

https://vuejs.org/guide/typescript/overview.html#definecomponent

TypeScript として コンポーネント を記載するためには、 以下のように script タグ 内で defineComponent を 記載する必要があります。 こうすることで 型推論 も有効になります。

とりあえず 先に進めるためには “おまじない” だと思って 以下を script タグ 内に記載すれば問題ありません。

import { defineComponent } from 'vue'
export default defineComponent()

TypeScript 固有の約束事が理解できてきたところで TypeScript ならではの機能を コンポーネント に実装していきたいと思います。

型推論 (defineCompent) について

ここで少し 型推論 について補足しておきます。 型推論 とは 変数宣言時に 文字列型 や 数値型 という型を指定しなくても プログラミング 言語の内部としては プログラミング の文脈から 型を推測して 型を保持するというものです。 C 言語などでは変数宣言時に型の指定が必須でしたが、 JavaScript や TypeScript, Python などでは型の指定は必須ではないため 型推論 が必要になってきます。 

TypeScript における 型推論 (Type Inference) については 以下の リンク を参考にしてみてください。

Documentation - Type Inference
How code flow analysis works in TypeScript

TypeScript ならではの機能を コンポーネント に実装

[ads]

TypeScript ならではの機能にはいくつかありますが、ここでは Interfaces を取り上げたいと思います。

Interfaces

Interface とは 以下の例のように 型 を指定された 変数 をまとめて定義したものです。 ここでは 人名 (name: string 型) と 身長 (height: number 型) をまとめて 人 (Person) として定義しています。

interface Person {
  name: string
  height: number
}

それでは、 この Person インターフェース を 画面上に表示するような実装をしていきたいと思います。

インターフェース を アプリケーション に表示するよう実装

今回は、 以下のように Person インターフェース の オブジェクト として david を作成し その内容を 表示するように実装してみます。

script タグ

script タグ には 以下のような内容を記載していきます。

  • defineComponent を import
  • interface Person を定義
  • export default として defineComponent を指定
    • defineComponent の中に data() を定義
    • data() として Person インターフェース オブジェクト の david を return するようにする
import { defineComponent } from 'vue'
 
interface Person {
 name: string
 height: number
}
 
export default defineComponent({
  data() {
   return {
     david: {
       name: 'David Beckham',
       height: 180.1
     } as Person
   }
 }
})

template タグ

画面に表示する template 部分 は以下のように記載します。

  • Person インターフェース の name を 姓名 で分割表示
  • Person インターフェース の height を 小数点以下第二位 まで補完して表示
 {{ david.name.split(' ')}}
 {{ david.height.toFixed(2) }}

実行結果

上記の内容で実行すると以下のような出力となります。

期待した通り、 性と名が分割表示され、 身長が 小数点以下まで表示していることが確認できます。

VSCode 上での 型 チェック

TypeScript で簡単な アプリケーション を作成することができましたが、 TypeScript の重要な特徴である 型 チェック についても確認していきたいと思います。

先ほどの template に記載した内容を以下のように変更してみます。本来  split メソッド は string 型に対してのみ有効なため number 型の height に対しては エラー となります。

  {{ david.height.split(' ')}}
  {{ david.height.toFixed(2) }}

実際に試してみると、 記載を変更した瞬間に VSCode 上で 以下のように エラー が チェック され 通知してくれます。 

JavaScript で同様の コード を記載して実行すると 上記のような 型 チェック はされないため エラー に気づかず ビルド して 実行 してしまうこともあり得ます。 当然、 実行後 ブラウザ の コンソール には以下のように エラー は表示されるのですが、 エラー の指摘は早ければ早い方が良いですよね。

[ads]

まとめ

[ads]
  • TypeScript コンポーネント は 拡張子 vue で作成
  • script タグ 
    • lang=”ts” を記載
    • defineComponent を import し記載
  • Interface は 変数を 型 と共に定義するもの
  • TypeScript では 型 チェック による エラー チェック が有効

関連記事

[ads]

本記事で使用した サンプルコード

script

<script lang="ts">
import { defineComponent } from 'vue'
 
interface Person {
 name: string
 height: number
}
 
export default defineComponent({
  data() {
   return {
     david: {
       name: 'David Beckham',
       height: 180.1
     } as Person
   }
 }
})
</script>

template

<template>
 {{ david.name.split(' ')}}
 {{ david.height.toFixed(2) }}
</template>

Ads