Using Vue with TypeScript - 型付き開発基盤の全体像

ロードマップ: Vue.js学習ロードマップ

What(何についてか)

Vue 3 における TypeScript 利用の全体像を整理する。対象は個別APIの細かな型付けではなく、プロジェクト作成、IDE、vue-tsctsconfig.json、Single-File Components、template 式まで含めた型付き開発基盤である。

Why(なぜ必要か)

TypeScript は静的解析によってビルド前に不整合を検出し、大規模な変更やリファクタリングの安全性を高める。Vue では UI 状態、props、template 式が密接に結びつくため、script だけでなく template を含む一貫した型システムが重要になる。

特に Vue 3 では、Composition API と <script setup> を中心とする開発スタイルが一般的であり、TypeScript を前提にすると IDE 補完、エラー早期検出、コンポーネント境界の契約明確化が大きく改善される。

How(どう動くか)

1. Vite と型チェックは役割分担する

Vite ベースの Vue プロジェクトでは、開発サーバは高速性を優先し、TypeScript の**変換(transpile)**のみを担当する。型エラーの検出は主に IDE と vue-tsc が担当する。

flowchart LR
  A[".vue / .ts ソース"] --> B["Vite / esbuild\n高速変換"]
  A --> C["IDE / Vue Language Server\n即時フィードバック"]
  A --> D["vue-tsc\nCLI型チェック"]
  B --> E["開発サーバ実行"]
  C --> F["編集時エラー検出"]
  D --> G["CI / ローカル最終確認"]

この分離により、開発時の体感速度を落とさずに型安全性を維持できる。

2. SFC では lang="ts" が型の入口になる

Single-File Components では <script lang="ts"> または <script setup lang="ts"> を使うことで、script と template の両方に型チェックが適用される。

<script setup lang="ts">
import { ref } from 'vue'
 
const count = ref(1)
</script>
 
<template>
  {{ count.toFixed(2) }}
</template>

この構成では countRef<number> と推論されるため、template 側でも number として安全に扱える。

3. template 式も TypeScript の監視対象になる

Vue の template は単なる HTML 断片ではなく、状態を参照する式の実行場所である。そのため、union 型などは template 側でも厳密に評価される。

<script setup lang="ts">
let x: string | number = 1
</script>
 
<template>
  {{ (x as number).toFixed(2) }}
</template>

型アサーションで回避はできるが、実務では script 側で型を絞る、computed で整形するなど、template に複雑な型判断を持ち込まない設計が望ましい。

4. tsconfig.json は Vite の実行モデルに合わせる

Vue + Vite の TypeScript 設定では、単に厳格性を上げるだけでなく、ビルドツールの変換方式に合わせる必要がある。

主なポイントは以下の通り。

項目役割
isolatedModulesファイル単位変換と整合する前提を強制する
verbatimModuleSyntaxモジュール構文を保ちつつ、現代的な設定として isolatedModules を包含する
strict厳格な型チェックを有効にし、特に Options API の this を安全に扱う
paths@/* のようなエイリアスを TypeScript に共有する
jsx, jsxImportSourceTSX を使う場合の設定

5. defineComponent() は型付きコンポーネント定義の入口になる

Options API や setup() を直接使う場合は defineComponent() によって props や thissetup(props) の型推論が有効になる。

import { defineComponent } from 'vue'
 
export default defineComponent({
  props: {
    message: String
  },
  setup(props) {
    props.message
  }
})

ただし、Composition API + <script setup> では defineComponent() を明示的に書く機会は少なく、現在の主流は <script setup lang="ts"> を基準に考える。

6. Composable も .ts モジュールとして自然に型付けできる

Composable は Vue 専用の特殊形式ではなく、状態を持つ再利用関数として扱える。したがって、TypeScript では通常の .ts モジュールとして定義し、推論または明示型で利用する。

// mouse.ts
import { ref, onMounted, onUnmounted } from 'vue'
 
export function useMouse() {
  const x = ref(0)
  const y = ref(0)
 
  function update(event: MouseEvent) {
    x.value = event.pageX
    y.value = event.pageY
  }
 
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))
 
  return { x, y }
}
<script setup lang="ts">
import { useMouse } from './mouse'
 
const { x, y } = useMouse()
</script>

通常は拡張子なしで ./mouse と import し、ビルドツールと TypeScript に解決させる。公式ドキュメントの ./mouse.js は JavaScript 版の例である。

Options API → Composition API 差分(補足)

項目Options API(旧)Composition API(新)
コンポーネント定義defineComponent({ data, methods, mounted })<script setup> 内で直接 state と関数を定義
this 依存this 経由で props / state / methods にアクセスthis を使わず変数参照で完結
型付けの難所this の型推論に strict が重要ref, computed, 関数戻り値の推論が中心
主流の書き方補助的、既存コード理解向け現行の学習と実務の中心

Key Concepts

用語説明
ViteVue 公式推奨の高速ビルドツール。開発時は TypeScript を変換するが型チェックは主担当ではない
vue-tscVue SFC を理解した TypeScript CLI。CI やローカル確認で型エラーを検出する
SFC.vue 形式の Single-File Component。template, script, style を1ファイルで扱う
<script setup lang="ts">Composition API を簡潔に書きつつ TypeScript を有効化するモダンな基本形
defineComponent()Vue コンポーネントとして型推論を有効にするラッパ関数
isolatedModulesファイル単位変換を前提とする TypeScript 設定
composable状態や副作用を再利用するための関数モジュール。通常の .ts として型付けできる