未経験の方がClaude CodeやCopilotでTypeScriptを書き始めると、動くコードはすぐ出るのに、エディタに**赤い波線(型エラー)**が残ることがよくあります。
このとき一番やりがちなのが、any や @ts-ignore で消してしまうこと。実際、AI自身に「エラー消して」と頼むと、平気で any を差し込んで返してくることがあります。動いてしまうので気づきにくいのですが、これはTypeScriptを入れた意味を自分で捨てている状態です。
この記事では、AIが生成したコードで頻出する型エラーを3つ、実際のコード片とエラーメッセージで示し、「なぜ握りつぶすと危険か」→「AIにどう頼めばanyを使わず型で直せるか」を深掘りします。
前提:any と @ts-ignore が"消してるだけ"な理由
TypeScriptの型エラーは、多くの場合「実行時に落ちる可能性がある箇所」を事前に教えてくれています。any を入れると、その箇所の型チェックが丸ごと無効化され、以降のプロパティアクセスも一切検査されなくなります。@ts-ignore は、その行のエラーを理由を問わず黙らせるだけです。
つまり、赤い波線は消えますが、バグの可能性はコードに残ったままになります。しかも消えているので、後から自分でも気づけません。
まずは tsconfig.json で strict: true(最低でも strictNullChecks: true)が入っている前提で話を進めます。これが無いと、そもそも危険なエラーが波線として出てきません。
{
"compilerOptions": {
"strict": true
}
}
ケース1:Object is possibly 'null'
DOM操作やAPIのレスポンスで最頻出です。AIに「フォームの値を取得して」と頼むと、こういうコードが返ってきがちです。
const input = document.getElementById("email");
console.log(input.value);
// ~~~~~ Object is possibly 'null'.
getElementById は要素が無ければ null を返すので、戻り値の型は HTMLElement | null。null のときに .value を触ると実行時に Cannot read properties of null で落ちます。TypeScriptはそれを事前に警告しています。
未経験がやりがちなミス
const input = document.getElementById("email") as any;
console.log(input.value); // 波線は消えるが、nullなら本番で落ちる
as any で波線は消えますが、input が null の可能性は何も解決していません。IDのタイプミス一つで本番エラーです。
型で直す
null のケースを明示的に処理し、要素の種類も絞り込みます。
const input = document.getElementById("email");
if (input instanceof HTMLInputElement) {
console.log(input.value); // ここでは input は HTMLInputElement 確定
} else {
console.warn("email input が見つかりません");
}
instanceof で絞り込むと、null でないことに加えて「.value を持つ HTMLInputElement である」ことまで型で保証されます。
AIへの頼み方
このコードで "Object is possibly 'null'" が出ています。
input が null の場合を握りつぶさず処理してください。
また .value を使いたいので HTMLInputElement であることを型で絞り込んでください。
any と @ts-ignore は使わないでください。
ポイントは、**状況(何のエラーか)+期待する型(HTMLInputElementを使いたい)+禁止事項(any/ts-ignore禁止)**をセットで渡すことです。ここまで指定しないと、AIは楽な方(any)に逃げます。
ケース2:Type 'string | undefined' is not assignable to type 'string'
環境変数や配列アクセス、オプショナルなプロパティで頻出します。
function greet(name: string) {
return `Hello, ${name}`;
}
const user = { name: "Sato", nickname: undefined as string | undefined };
greet(user.nickname);
// ~~~~~~~~~~~~~ Argument of type 'string | undefined'
// is not assignable to parameter of type 'string'.
nickname は undefined かもしれないのに、greet は string しか受け取りません。
未経験がやりがちなミス
greet(user.nickname!); // ! で「絶対ある」と言い切る
!(非nullアサーション)は as any に近く、「無いはずない」と開発者が保証するという意味です。実際に undefined が来たら、やはり実行時に落ちます。
型で直す
「無いとき」の値を用意するか、関数側で undefined を受け入れます。
// A: 呼び出し側でフォールバック
greet(user.nickname ?? user.name);
// B: 関数定義を差し替え、undefined を許容する設計にする
function greet(name: string | undefined) {
return `Hello, ${name ?? "guest"}`;
}
??(Null合体演算子)は「左が null/undefined のときだけ右を使う」ので、型が string に確定します。
AIへの頼み方
"Type 'string | undefined' is not assignable to type 'string'" が出ています。
undefined の可能性を ! で潰さず、undefined のときのフォールバック値を
?? で用意する形に直してください。any と ! と @ts-ignore は禁止です。
! も明示的に禁止に入れるのがコツです。禁止しないとAIは ! で"それっぽく"直してきます。
ケース3:Property 'xxx' does not exist on type
AIがAPIレスポンスを扱うコードを書くと、これがよく出ます。
async function getUser() {
const res = await fetch("/api/user");
const data = await res.json(); // data の型は any
return data.userName; // any なので何も検査されない
}
res.json() の戻り値は any(正確には Promise<any>)です。ここで data.userName と書けてしまいますが、実際のAPIが user_name を返していたら undefined。エラーも波線も出ず、一番見つけにくいバグになります。逆に data を unknown で受けてからプロパティに触ろうとすると、今度は 'data' is of type 'unknown'.(型が不明なので触らせない)という波線が出て、「まず形を確認しろ」と促されます。
未経験がやりがちなミス
const data = await res.json() as any;
return data.userName; // 打ち間違えても気づけない
any にした瞬間、TypeScriptは「このオブジェクトに何があるか」を一切チェックしなくなります。
型で直す
期待する形を型(interface)で定義して、そこに合わせます。
interface User {
id: number;
userName: string;
}
async function getUser(): Promise<User> {
const res = await fetch("/api/user");
const data: unknown = await res.json();
// 実行時に本当にその形かを確認してから User として扱う
if (
typeof data === "object" && data !== null &&
"id" in data && "userName" in data
) {
return data as User;
}
throw new Error("APIレスポンスの形が想定と違います");
}
いったん unknown で受け、in 演算子で中身を確認してから User に絞り込みます。こうすると data.userName のタイプミスは即座に波線で分かり、実行時の想定外レスポンスも throw で検知できます。
AIへの頼み方
fetch のレスポンスを any で受けないでください。
期待するレスポンスは { id: number; userName: string } です。
これを interface User として定義し、res.json() は unknown で受けてから
User かどうかを実行時にチェックして絞り込む形にしてください。
any と @ts-ignore は使わないでください。
「期待するレスポンスの形」を具体的に渡すのが最重要です。形を教えないと、AIは推測で any に逃げます。
まとめ:赤い波線への向き合い方
-
any/@ts-ignore/!はエラーを消すだけで、危険は残す - AIへの依頼は「状況(エラー文)+期待する型+"anyやts-ignoreを使わずに"の明示」の3点セット
-
nullは絞り込み、undefinedは??、anyなレスポンスはunknown+実行時チェック
面白いのは、この「AIに型で直させる」やり取りをしていると、TypeScriptの型の考え方そのものがAIとの対話で身についていくことです。プログラミングの知識とAI協働のスキルが同時に鍛えられる。ここは独学の型学習とは違う、AI時代ならではの学び方だと感じています。
※この記事は未経験〜駆け出し向けです。中上級の方には物足りないので、社内研修・後輩育成・知り合いへの紹介にどうぞ。
未経験から Next.js + Supabase + Claude Code でWebアプリを作って公開するまでを全20セッションで体系化した教材を作っています。
- 無料で試す(未経験向け体験版)→ https://github.com/ayies128/next-ai-camp-trial
- 教材完全版+チャットサポート(月5,500円・面談なし)→ https://menta.work/plan/20251?ref=qiita
- AI×開発ニュースを毎日発信 → YouTube『AIエンジニア情報局』(別運営チャンネル)