エラーの発生シナリオ
このエラーは通常、変数を本来なり得ない型に強制的に変換しようとしたときに発生します。TypeScriptは「オーバーラップ(重複)」を確認します。つまり、これら2つの型が共通の部分を持つ可能性があるかどうかをチェックします。答えが完全に「ノー」である場合、コンパイラは実行時の深刻なバグを防ぐためにアサーションをブロックします。
開発者がAPIから取得した文字列を直接数値にキャストしようとする、よくある間違いを見てみましょう。
const priceInput = "49.99";
// ここでエラーが発生します:
// Conversion of type 'string' to type 'number' may be a mistake...
const price = priceInput as number;
分析:なぜTypeScriptはブロックするのか
TypeScriptでは、一方の型がもう一方の型のサブタイプである場合にのみ、型アサーション(asキーワード)が許可されます。家系図のようなものを想像してください。ボタンは要素の一種であるため、汎用的なHTMLElementを特定のHTMLButtonElementにキャストできます。これらは共通のプロパティを共有しています。
stringやnumberのようなプリミティブ型は異なります。これらは完全に別の枝に属しています。"123"という文字列は、コンパイラの目から見れば数値の123とは全く別物です。文字列に対して強制的にas numberを適用することは、実行環境に対して嘘をついていることになります。この嘘は、計算操作中のNaNの結果やアプリのクラッシュにつながります。
クイックフィックス:ダブルキャスト
複雑なサードパーティデータを扱っていて、結果が100%確実な場合があります。そのような稀なケースでは、unknownへの中間キャストを使用することで安全チェックをバイパスできます。エラーメッセージ自体もこの解決策を提案しています。
const priceInput = "49.99";
// ステップ1: unknown(トップタイプ)にキャスト
// ステップ2: ターゲットの型にキャスト
const price = (priceInput as unknown) as number;
**注意:**これにより赤い波線は消えますが、データ自体は変わりません。実行時、priceは依然として文字列の"49.99"です。price.toFixed(2)を呼び出すと、toFixedは数値のメソッドであり、文字列のメソッドではないため、アプリはクラッシュします。
恒久的な対策:実際のデータ変換
ほとんどの場合、必要なのはキャストではなく**変換(コンバージョン)**です。キャストはコンパイラに「見逃してくれ」と頼むものですが、変換は実際の値を正しい形式に変更します。
文字列から数値への変換
標準的なJavaScriptのメソッドを使用しましょう。これらの方が安全で読みやすいです。
const priceInput = "49.99";
// オプションA: Numberコンストラクタ(厳密な変換に最適)
const price = Number(priceInput);
// オプションB: parseFloat(複雑な文字列から小数を抽出するのに適しています)
const priceFloat = parseFloat(priceInput);
オブジェクトの非互換性の修正
インターフェースが一致しない場合、マッピング関数が非常に役立ちます。APIが文字列のIDを返し、UIが数値を必要とする場合は、無理やりキャストするのではなく、マッピングを行いましょう。
interface UserResponse {
user_id: string; // 例: "101"
user_name: string;
}
interface AppUser {
id: number; // 例: 101
name: string;
}
const rawData = { user_id: "101", user_name: "Alice" } as UserResponse;
// 型が一致するように手動でデータをマッピングする
const user: AppUser = {
id: parseInt(rawData.user_id, 10),
name: rawData.user_name
};
テストにおける「不完全な」オブジェクトの処理
このエラーはユニットテスト中によく発生します。巨大なインターフェースの数個のフィールドだけをモックしたい場合、提供するオブジェクトが小さすぎると、TypeScriptは型がオーバーラップしていないと警告します。
Partial<T>を使用するのが、通常最もクリーンな解決策です。これにより、一部のプロパティのみを提供することをTypeScriptに伝え、安全でないキャストに頼ることなく型を再び「オーバーラップ」させることができます。
検証チェックリスト
コードをリリースする前に、次の3つのステップで修正を確認してください:
- 実行時の型を確認する:
console.log(typeof price)を追加します。"number"と出力され、"string"ではないことを確認してください。 - 計算操作を試す: 結果に10を足してみます。
"49.99" + 10が"49.9910"になる場合、キャストは「成功」していますがロジックは失敗しています。59.99になれば成功です。 - コンパイラを確認する: ターミナルから
tsc --noEmitを実行します。エラーが完全に解消されていることを確認してください。

