【実務・中級編】Cursorエディタでの『型駆動開発(Type-Driven Development)』:AIにエラーを出させないための静的解析連携術 – 軽量・高機能テキストエディタ生産性向上バイブル

はじめに:AIの「ハルシネーション」と型駆動開発の融合点

テックリードとしてチームのコードベースを見渡したとき、AIアシストコーディングの恩恵と同時に、一つの大きな構造的課題に直面していないだろうか。

「AIが生成したコードは一見美しく動くように見えるが、既存のドメインモデルや厳格な型制約を無視しており、ビルドを通すために人間のエンジニアが修正に追われる」

この現象の本質は、LLM(大規模言語モデル)が「確率的に尤もらしい文字列」を出力しているにすぎず、プロジェクトが持つ決定論的な「型(Type)」の世界を完全には理解していないことに起因する。

Cursorは、単なるコード補完ツールではない。適切にコンテキストを与えれば、人間の代わりにコンパイラと対話し、エラーを自律的に修正し続ける「自律型開発エージェント」へと変貌する。本稿では、TypeScriptやRustなどの静的型付き言語において、CursorのAI機能と静的解析(LSP / Compiler)を完全に同期させ、「AIにそもそもコンパイルエラーを出させない」ための実践的な型駆動開発(Type-Driven Development)のアーキテクチャを解説する。

—

1. 内部メカニズム:CursorとLSP/コンパイラのデータフロー

まず、Cursorの内部で何が起きているのかを把握しよう。CursorはVS Codeのフォークであり、LSP(Language Server Protocol)のクライアントとして動作している。

一般的なAIエディタのワークフローは以下の通りだ。
1. ユーザーがプロンプトを入力する。
2. AI(Claude 3.5 SonnetやGPT-4o)がコードを生成する。
3. エディタに書き込まれ、そこで初めてコンパイラやLSPがエラーを検知する。
4. 人間がエラーを見て、再度AIに修正を指示する。

この往復(Round-trip)こそが開発者の認知負荷を高め、フロー状態を分断するボトルネックである。

これを打破するためには、「CursorのComposer(Ctrl+I / Cmd+I)やChat(Ctrl+L / Cmd+L)のコンテキストに、静的解析の診断結果(Diagnostics)をリアルタイムかつ構造化してインジェクトする」必要がある。AIがコードを書く「その瞬間」に、型定義とコンパイラの怒りの声(エラーメッセージ)がプロンプトの裏側で共有されていれば、ハルシネーションの確率は劇的に低下する。

—

2. 開発スピードを極限まで高める隠れたキーボードショートカット

プロフェッショナルなエンジニアはマウスを使わない。Cursorの真価を引き出す、手首の移動を最小限にするショートカット群だ。

  • `Cmd + I` (Mac) / `Ctrl + I` (Windows/Linux) : Composerの起動

複数ファイルを横断したリファクタリングや、新規モジュールの型定義からのボトムアップ実装に用いる。

  • `Cmd + Shift + I` : チャットへのコンテキスト直接指定

`@Files` や `@Docs` を瞬時に呼び出し、特定の型定義ファイル(`types.ts` や `schema.rs`)をAIのワーキングメモリに固定する。

  • `Cmd + K` : インライン編集(Inline Edit)

選択した関数や型エイリアスに対し、「このインターフェースにオプショナルなプロパティを追加し、関連するバリデーターも同時に更新して」といった局所的な型安全リファクタリングを1秒で実行する。

  • `Option + Enter` (Mac) / `Alt + Enter` (Windows/Linux) : Quick FixからのAI委譲

LSPが検知した型エラー(例:`Type ‘string’ is not assignable to type ‘UserId’`)に対し、Quick FixメニューからシームレスにAIへ修正をプロンプト送信する。

—

3. 型駆動開発を加速させる絶対入れるべき神プラグイン

CursorはVS Codeの拡張機能エコシステムをそのまま継承している。型駆動開発を極めるために、以下の拡張機能は必須のインフラストラクチャである。

1. Error Lens

  • 理由: コード行のインラインにコンパイラエラーや警告を直接描画する。AIが生成したコードのどこに型不整合があるかを視覚的ノイズなしで一瞬で把握できるため、CursorのインラインAI修正へのトリアージが爆速化する。

2. TypeScript Vue Plugin (Volar) / Rust Analyzer (言語ごとの公式LSP)

  • 理由: AIに渡る前の段階で、正確な型推論ツリーをメモリ上に構築する。CursorのAIはこのLSPが提供するシンボル情報をベースにコンテキストを構築するため、拡張機能の選定がそのままAIの頭脳の良さに直結する。

3. GitLens

  • 理由: 「なぜこの型制約が追加されたのか」というコンテキスト(Blame)をAIチャット(`@commits`)に即座に読ませることで、破壊的変更を未然に防ぐ。

—

4. チーム開発で役立つ設定の共有化ルール(.cursorrulesの極意)

チーム全員が同じ品質のAI出力を得るためには、プロジェクトルートに配置する `.cursorrules` ファイルの設計が極めて重要である。個人のプロンプト依存を脱却し、リポジトリ自体に「AIへの厳格なコーディング規約」をコードとして落とし込む。

以下に、TypeScript / Zodを用いた型駆動開発を強制するための `.cursorrules` のベストプラクティスを示す。

{
“$schema”: “https://cursor.com/cursorrules.schema.json”,
“project_type”: “TypeScript Monorepo with Domain-Driven Design”,
“ai_instructions”: {
“core_principles”: [
“Type-Driven Development (TDD): Implement types/interfaces BEFORE writing implementation logic.”,
“Never use ‘any’ or ‘unknown’ casting unless explicitly requested with a justifiable safety comment.”,
“Rely on Zod for runtime validation, and infer TypeScript types using ‘z.infer‘.”,
“Always check existing type definitions in ‘src/types/’ before creating new primitive types.”
],
“error_handling”: [
“Use discriminated unions for result types (e.g., Result) instead of throwing arbitrary errors.”,
“Ensure all switch statements over union types are exhaustive (use a never-type helper).”
],
“code_generation_rules”: [
“When generating a new API endpoint, define the request/response DTOs first.”,
“Refrain from modifying core infrastructure types without explicit user confirmation.”
]
},
“context_management”: {
“always_include”: [
“tsconfig.json”,
“src/types/index.ts”
]
}
}

この設定ファイルをプロジェクトに配置することで、CursorのAIは「勝手に `any` を使ってコードを通す」という悪癖を断ち切り、プロジェクト固有の厳格な型ルールに準拠したコードを生成するようになる。

—

5. 実用的な設定ファイル(JSON)のベストプラクティス構成例

Cursorの挙動をプロジェクトの型システムに最適化するため、`.vscode/settings.json`(またはCursor共通設定)に記述すべき設定の全貌を解説する。型チェックの厳格化とAIの邪魔をしない非同期処理のバランスをチューニングしている。

{
// 保存時の自動フォーマットと型安全なインポート整理を有効化
“editor.formatOnSave”: true,
“editor.codeActionsOnSave”: {
“source.fixAll.eslint”: “explicit”,
“source.organizeImports”: “explicit”
},

// TypeScriptの型チェックをプロジェクト全体で最高レベルに引き上げる
“typescript.updateImportsOnFileMove.enabled”: “always”,
“typescript.suggest.completeFunctionCalls”: true,

// Cursor特有のAI機能を型駆動開発に最適化する設定
“cursor.chat.codeGeneration.useProjectContext”: true,
“cursor.cpp.enablePartialAcceptances”: true,

// リアルタイム診断をAIのコンテキストに密に連携させるためのファイル監視除外設定
“files.watcherExclude”: {
“/.git/objects/“: true,
“/node_modules/“: true,
“/dist/“: true,
“/.next/“: true
},

// インラインサジェスト(Ghost Text)の速度調整
// 型推論の妨げにならないよう、曖昧な予測よりもLSPの確定を優先
“cursor.cpp.toggle”: true
}

この設定により、LSPによる静的解析が常に最優先で走る環境を作り出し、その解析結果をCursorのAIがバックグラウンドで安全に参照できるパイプラインが完成する。

—

6. 実践:型駆動開発のワークフロー(実例)

実際にCursor上で型駆動開発を行う際の具体的なステップを示す。

1. 型の定義(人間またはAIのComposer)
まずは `src/domain/user.ts` にドメインモデルの型を定義する。

export type UserId = string & { readonly __brand: unique symbol };

export interface UserProfile {
id: UserId;
email: string;
tier: ‘FREE’ | ‘PRO’ | ‘ENTERPRISE’;
}

2. AIへのインライン指示(`Cmd + K`)
実装ファイルを開き、次のように指示する。
> 「UserProfileを受け取り、StripeのカスタマーIDを非同期で生成する関数を実装して。ただし、型エラーやany型は一切禁止。Result型を用いること」
3. LSPとAIの協調動作
AIがコードを出力した瞬間、もし型に不整合があれば `Error Lens` とLSPが赤線を引く。ユーザーは `Option + Enter` -> 「Fix with AI」を叩くことで、コンパイラのフィードバックをループさせた自己修復をAIに実行させる。

このサイクルを回すことで、人間は「コンパイルを通すための泥臭い作業」から解放され、「ビジネスロジックと型の設計」という本質的なアーキテクチャ構築に集中できるようになる。

—

おわりに:型はAIへの最高のラブレターである

LLM時代のエンジニアリングにおいて、コード量やタイピングスピードはもはや競争力の源泉ではない。「コンピュータとAIに対して、どれほど厳格で美しい制約(型)を与えられるか」こそが、プロダクトの拡張性と品質を決定づける。

Cursorを単なる「賢いコード補完マシン」として使う段階は今日で終わりにしよう。型定義をコンパスとし、LSPを羅針盤としてCursorを駆動させるとき、あなたの開発チームは真の「型駆動開発」のスピードを手に入れることになる。

タイトルとURLをコピーしました