Using Vue with TypeScript - 型付き開発基盤の全体像
ロードマップ: Vue.js学習ロードマップ
What(何についてか)
Vue 3 における TypeScript 利用の全体像を整理する。対象は個別APIの細かな型付けではなく、プロジェクト作成、IDE、vue-tsc、tsconfig.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>この構成では count が Ref<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, jsxImportSource | TSX を使う場合の設定 |
5. defineComponent() は型付きコンポーネント定義の入口になる
Options API や setup() を直接使う場合は defineComponent() によって props や this、setup(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
| 用語 | 説明 |
|---|---|
| Vite | Vue 公式推奨の高速ビルドツール。開発時は TypeScript を変換するが型チェックは主担当ではない |
vue-tsc | Vue 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 として型付けできる |