マガジン

TypeScriptでゲームを書くメリット:AI生成コードとの相性

遊びをつくる

執筆にClaudeを使用しています。

一枚の紙からボールや足場、旗のある小さなゲーム世界が立ち上がるペーパークラフト
記事のテーマをもとに制作したAI生成イラスト。

ブラウザゲームをAIツールで作ろうとすると、生成されたコードが途中で動かなくなったり、修正を重ねるうちに何が何を参照しているか分からなくなったりする経験をお持ちではないでしょうか。その原因の多くは、JavaScriptの型のなさが引き起こす「変数の中身が実行してみるまでわからない」という状況にあります。 TypeScriptはJavaScriptに型注釈を加えた言語で、ブラウザで実行するにはいったんJavaScriptへ変換(トランスパイル)します。型をつけることで、AIが生成したコードの誤りをエディタ上で事前に検出でき、大規模なコードを自分で読み直すコストが大きく下がります。特に、一度に数百行を生成するAIツールとの組み合わせでは、TypeScriptの恩恵が顕著に現れます。 この記事では「なぜAI生成コードにTypeScriptが有効なのか」という核心から入り、実際にゲームプロジェクトへ導入するときの判断基準と手順を示します。

この記事の目次
  1. AIが生成するコードにTypeScriptが効く理由
  2. JavaScriptとの違いをゲーム文脈で整理する
  3. 環境構築:最短でプロジェクトを立ち上げる手順
  4. ゲームの状態管理でTypeScriptの型をどう設計するか
  5. 失敗しやすい点と対処
  6. 次の行動
  7. 参考資料

AIが生成するコードにTypeScriptが効く理由

AIがコードを生成するとき、変数名や関数名のつけ方は一貫していても、「この関数が受け取る引数の型」まで自動的に保証されるわけではありません。たとえば、プレイヤーの座標を扱うコードを何度かに分けて生成すると、最初は { x: number, y: number } というオブジェクトを渡していたのに、後の生成では [number, number] という配列を渡す形に変わっていた、という事態が起こります。JavaScriptではどちらも実行できてしまうため、画面には何も表示されずにゲームが止まります。

TypeScriptでは引数の型を明示するため、二つ目の生成コードを貼り付けた瞬間にエディタが赤線を引いて「型が合っていない」と教えてくれます。エラーの場所が行番号で確定しているので、「どこで壊れたか」を探す時間がほぼゼロになります。これは自分でコードを書いている場合にも効果がありますが、AIに任せた部分が多いほど恩恵は大きくなります。

もう一つの理由はコードの自己説明性です。TypeScriptで書かれた関数は、引数と戻り値の型が宣言に含まれています。

typescript
function movePlayer(player: Player, dx: number, dy: number): Player { ... }

このシグネチャを見れば、関数が何を受け取って何を返すかが一目で分かります。次にAIへ「この関数を拡張して」と依頼するとき、型情報をプロンプトに貼るだけで、AIはより正確なコードを返しやすくなります。型がドキュメントの役割を果たすため、人間とAIの両方にとって読みやすいコードになります。

JavaScriptとの違いをゲーム文脈で整理する

ゲーム開発に限った文脈で、両者の違いを整理します。

  • AIの生成コードを貼り付けたとき、JavaScript:実行するまでエラーが分からない、TypeScript:貼り付け直後にエディタで検出できる
  • 長い関数の引数を変更するとき、JavaScript:呼び出し箇所を手動で探す必要がある、TypeScript:エディタが全呼び出し箇所を一覧できる
  • ゲーム状態(スコア・HP等)の管理、JavaScript:オブジェクトのキーをタイポしても気づきにくい、TypeScript:存在しないキーへのアクセスが即エラーになる
  • 別のAIセッションで続きを書くとき、JavaScript:型情報が暗黙的で伝えにくい、TypeScript:型定義をそのままプロンプトに渡せる

TypeScriptには「型を書く手間」という追加コストがあります。ただしAIを使うなら、型定義そのものをAIに生成させることができます。ゲームの設計をざっくり伝えて「Player型とEnemy型を定義して」と依頼するだけで、型の骨格を受け取れます。自分で一から書く必要はありません。

環境構築:最短でプロジェクトを立ち上げる手順

TypeScriptのセットアップは、ゲームの規模や使うフレームワークによって最適解が変わります。ここでは「HTML+TypeScript」でブラウザゲームを始める典型的な手順を示します。

前提:Node.jsがインストールされていること。

  1. プロジェクトフォルダを作成し、ターミナルで移動する。
  2. npm init -y を実行してpackage.jsonを生成する。
  3. npm install --save-dev typescript でTypeScriptをインストールする。
  4. npx tsc --init を実行してtsconfig.jsonを生成する。
  5. tsconfig.jsonの "target" を "ES2020" 前後に、"outDir" を "./dist" に設定する。
  6. .ts ファイルを書いて npx tsc を実行すると、dist/ フォルダにJavaScriptが出力される。
  7. HTMLから dist/main.js を読み込む。

開発中は npx tsc --watch を使うと、ファイルを保存するたびに自動で変換が走るため、ブラウザをリロードするだけで最新の結果を確認できます。

より本格的にバンドラー(Viteやesbuildなどのビルドツール)を組み合わせると、複数ファイルを一本にまとめてブラウザに渡せるようになります。Viteは npm create vite@latest の対話式セットアップで「Vanilla」と「TypeScript」を選ぶだけで環境が整うため、初めてTypeScriptを試す場合はViteから入るのが手間が少ないです。最新の手順は各ツールの公式ドキュメントで確認してください。

ゲームの状態管理でTypeScriptの型をどう設計するか

ゲーム開発でTypeScriptを使うとき、最初に設計すべきは「ゲームの状態を表す型」です。スコア、プレイヤーのHP、現在のステージ番号といった情報を一つのオブジェクト型にまとめておくと、AIへの依頼も整理されます。

たとえば次のような型定義から始めます。

typescript
type GameState = {
  score: number;
  playerHP: number;
  stage: number;
  isGameOver: boolean;
};

この型定義をプロンプトに含めて「この状態を受け取り、プレイヤーがダメージを受けたときの新しい状態を返す関数を書いて」と依頼すると、AIは型に沿った関数を返します。引数や戻り値が型に合っていなければエディタが検出するため、生成物をそのまま受け入れるのではなく、型レベルで検証してから使うという流れが自然に作れます。

ゲーム状態をイミュータブル(不変)に扱う——つまり状態を直接変更せず、変更した新しいオブジェクトを返す——スタイルにすると、デバッグがさらに楽になります。TypeScriptの Readonly<GameState> のような型を使えば、意図しない変更をコンパイル時に防げます。

失敗しやすい点と対処

any 型の多用: AIが生成するコードには、型が定まらない変数に any を使うことがあります。any は型チェックを無効化するため、TypeScriptの恩恵が失われます。tsconfig.json で "noImplicitAny": true を設定しておくと、暗黙の any をエラーとして扱えます。明示的に any を書いている箇所は、実際の型に置き換えることを目標にしてください。

型とロジックを一緒に生成させる: 大きな機能を一度に生成させると、型とロジックが混在して修正しにくくなります。「まず型定義だけ生成させる→その型を使うロジックを生成させる」という2段階の依頼にすると、型の齟齬が出にくくなります。

トランスパイルエラーと実行エラーの混同: TypeScriptのエラーは実行前に検出される「型エラー」と、実行中に発生する「実行エラー」の2種類があります。型エラーはエディタとコンパイラが教えてくれますが、実行エラーは引き続きブラウザのコンソールで確認します。両方を別のものとして把握しておくと、原因の切り分けが速くなります。

次の行動

まずは既存のJavaScriptファイルの拡張子を .ts に変え、npx tsc --noEmit を実行して型エラーの一覧を眺めてみてください。エラーの多くは変数の型が不明確な場所で、AIに「この変数の型を定義して」と依頼するだけで解消できます。型定義が固まったら、アソバースへZIPでアップロードして動作を確認するとよいでしょう。

参考資料

  • TypeScript公式ドキュメント(typescriptlang.org)
  • Vite公式ドキュメント(vitejs.dev)
  • MDN Web Docs — JavaScript リファレンス