型エラーの「典型パターン」を知っておく意味
型エラーは無限にあるように見えて、実はよく出るパターンはかなり限られています。
この「典型パターン」を押さえておくと、エラーを見た瞬間に「ああ、これはあのパターンね」と当たりがつくようになります。
ここでは、初心者がほぼ確実に遭遇する代表的な型エラーを、例と一緒にかみ砕いて整理していきます。
パターン1: 「型Aは型Bに代入できません」系(is not assignable to)
もっとも頻出のエラー構文
まず、圧倒的に見る回数が多いのがこれです。
let age: number = 20;
age = "30";
TypeScriptこのときのエラーはだいたいこうなります。
Type '"30"' is not assignable to type 'number'.
意味はシンプルで、「"30"(string)は number 型の場所には置けません」ということです。
この「is not assignable to」は、TypeScriptの型エラーの中核ワードだと思ってください。
関数の引数でも同じパターン
関数の引数でも同じ構造です。
function greet(name: string) {
console.log(`Hello, ${name}`);
}
greet(123);
TypeScriptエラー:
Argument of type 'number' is not assignable to parameter of type 'string'.
ここでも、「number を string を期待している場所に渡しているからダメ」と言われています。
このパターンを見たら、必ず「期待されている型」と「実際に渡している型」の両方を見る癖をつけてください。
パターン2: プロパティが「ない」か「足りない」系
Property ‘xxx’ does not exist on type ‘YYY’
存在しないプロパティを触ろうとしたときの定番です。
const user = { name: "Taro" };
console.log(user.age);
TypeScriptエラー:
Property 'age' does not exist on type '{ name: string; }'.
これは、「{ name: string } という型には age なんてプロパティは定義されていないよ」という意味です。
オブジェクトの形(型)と、実際に触ろうとしているプロパティがズレているときに出ます。
Property ‘xxx’ is missing in type ‘AAA’ but required in type ‘BBB’
オブジェクトを代入するときに「足りない」パターンもよく出ます。
type User = {
id: number;
name: string;
};
const u: User = {
id: 1
// name がない
};
TypeScriptエラー:
Property 'name' is missing in type '{ id: number; }' but required in type 'User'.
「User 型には name が必須なのに、今渡しているオブジェクトには name が missing(足りない)」という意味です。
このパターンを見たら、「型定義側で必須にしすぎていないか」「オブジェクト側で書き忘れていないか」を疑います。
パターン3: null / undefined かもしれない系
Object is possibly ‘null’ / ‘undefined’
これもかなりよく見るエラーです。
let name: string | null = null;
console.log(name.toUpperCase());
TypeScriptエラー:
Object is possibly 'null'.
「そのオブジェクト、null かもしれないのにメソッド呼んでない?」という警告です。string | null のようなユニオン型を使っているときに、null チェックをせずに使おうとすると出ます。
対処としては、たとえばこうです。
if (name !== null) {
console.log(name.toUpperCase());
}
TypeScriptこの if の中では、TypeScript が「name はもう null じゃない」と理解してくれるので、エラーは消えます。
「null を許すなら必ずチェックする」「そもそも null を許さない設計にする」のどちらかを選ぶポイントです。
パターン4: ユニオン型との不一致系
許されていない値を入れようとしたとき
リテラル型+ユニオン型を使い始めると、次のようなエラーに出会います。
type Status = "success" | "error";
let s: Status = "success";
s = "pending";
TypeScriptエラー:
Type '"pending"' is not assignable to type '"success" | "error"'.
ここでも構造は同じです。
実際の型: "pending"
期待される型: "success" | "error"
つまり、「Status 型は success / error しか許していないのに、pending を入れようとしている」ということです。
「型の選択肢を増やすべきか」「代入している値が間違っているか」を考える場面になります。
パターン5: any が混ざって型安全が崩れる系
‘any’ type implicitly has an ‘any’ type など
strict 設定だと、暗黙の any に対してもエラーが出ます。
function greet(name) {
console.log(`Hello, ${name}`);
}
TypeScriptエラー(例):
Parameter 'name' implicitly has an 'any' type.
「name の型が書かれていないから、暗黙に any になってしまっているよ」という警告です。
any は「何でも入るし、どこにでも代入できる」代わりに、型チェックをすり抜けてしまう危険な存在なので、基本は避けるべきです。
ここは素直にこう直します。
function greet(name: string) {
console.log(`Hello, ${name}`);
}
TypeScript「関数の引数には必ず型を書く」をルールにしてしまうと、この手のエラーはほぼ消えます。
パターン6: 戻り値の型と実際の return が合っていない系
Type ‘A’ is not assignable to type ‘B’(戻り値版)
戻り値の型注釈と、実際に返している値がズレているパターンです。
function getAge(): number {
return "20";
}
TypeScriptエラー:
Type 'string' is not assignable to type 'number'.
ここでも、「string を number を期待している場所(戻り値)に置こうとしているからダメ」と言われています。
戻り値の型を変えるか、返している値の型を変えるか、どちらが正しい設計かを考える必要があります。
パターン7: this やコンテキストの型が合わない系(少し先の話)
これは少しレベルが上がりますが、クラスや this を使い始めると出てくるパターンです。
const obj = {
value: 1,
getValue() {
return this.value;
}
};
const fn = obj.getValue;
// fn(); // this の型が合わない、などのエラーになることがある
TypeScriptここでは詳細には踏み込みませんが、「this の中身が何型だと推論されているか」がズレると、Property 'value' does not exist on type 'XXX' のようなエラーが出ることがあります。
これは「this を素の関数に切り離して使わない」「アロー関数を使う」など、設計側で避けることも多いです。
型エラーを「パターン」で見る癖をつける
ここまで見てきたように、型エラーはだいたい次のどれかに分類できます。
型Aを型Bの場所に置こうとしている(assignable to 系)
オブジェクトの形が合っていない(プロパティがない・足りない)
null / undefined かもしれないものをそのまま使っている
ユニオン型の選択肢にない値を入れようとしている
any に逃げていて、型が曖昧になっている
戻り値の型注釈と実際の return がズレている
エラーを見たときに、
「これは assignable パターンだな」
「これは missing property パターンだな」
とラベルを貼る癖をつけると、直し方もすぐに見えてきます。
