てもとツール
ガイド

APIレスポンスの型定義がずれる5つの原因と確かめ方

型を書いたのに実行時に undefined が来る、IDが別のレコードを指す。APIレスポンスと型定義が食い違う代表的な5つの原因を、見分け方と直し方に分けて整理しました。実データから型を起こし直して差分を取る手順も紹介します。

公開読了目安 約5分

この記事の要点

  • 型定義は実行時に何も検査しないので、ずれても誰も止めてくれない
  • 1件のレスポンスから起こした型は、省略される項目を必須にしてしまう
  • null と「キーが無い」は別物で、混ぜると分岐が抜ける
  • 安全に扱える整数を超えるIDを number で受けると値そのものが変わる
  • 実データを複数件集めて型を起こし直し、差分を取ると原因が絞れる
目次

型を書いたのに実行時に undefined が来る。その原因のほとんどは、型定義が間違っているのではなく、型を作ったときに見ていたデータが足りなかったことにあります。この記事では、型と実データが食い違う代表的な 5 つの原因を、見分け方と直し方に分けて整理します。

前提: 型定義は実行時に何も守らない

まずここを押さえてください。TypeScript の型は、コードを書いている間だけの約束です。

ビルドすると型の情報は消えます。実行時にサーバーから何が届いても、型が違うと言って止まることはありません。

つまり型と実データのずれは、誰も検出してくれないまま先へ進みます。気づくのは、そのデータを使った画面が壊れたときです。

原因1: 1 件のレスポンスから型を起こした

一番多いのがこれです。手元にあるサンプルのレスポンスを 1 件だけ見て型を書くと、そのとき返ってきた項目が全部必須になります。

省略されることがある項目は、無かった回のレスポンスを見ない限り分かりません。1 件では判断する材料がそもそも無いのです。

見分け方: 落ちた項目が、実データの一部にだけ存在するかを確かめます。3 件ほど並べて見比べれば分かります。

直し方: 抜けることがある項目に ? を付けます。そのうえで、使う側で有無を分岐させてください。

原因2: null と「キーが無い」を混ぜている

この 2 つは似て見えますが、届き方が違います。

届いたもの型での書き方読み出したときの値
"bio": nullbio: string | nullnull
bio というキーが無いbio?: stringundefined
どちらも起こりうるbio?: string | nullnullundefined

if (user.bio) のように真偽で分岐すると、どちらも同じ扱いになるので気づきません。問題が出るのは user.bio.length のように中身へ触ったときです。

見分け方: 実データで、そのキーが存在しない回null が入っている回の両方があるかを数えます。

直し方: 両方あるなら ?| null を両方書きます。片方しか無いなら片方だけにして、意図を型に残してください。

原因3: 大きな ID を number で受けている

外部サービスの ID には、19 桁前後の整数がよく使われます。JavaScript が正確に表せる整数は 9007199254740991 まで、つまり 16 桁です。

これを超える値は、JSON として読み込んだ時点で丸められます。型としては number で通り、エディタも実行時も何も言いません。

気づくのは、保存した ID が別のレコードを指していたときです。表示は正常に見えるぶん、発見がかなり遅れます。

見分け方: レスポンスの生テキストに書かれた数値と、読み込んだ後の値を見比べます。末尾が 000 になっていたら丸められています。

直し方: サーバー側が文字列で返せるならそれが最善です。返せないなら、テキストのまま取り出して文字列として扱ってください。

原因4: 日付を Date 型として書いている

JSON に日付という型はありません。"2026-08-27T10:00:00Z" は、あくまで文字列として届きます。

型定義に createdAt: Date と書くと、その場では通ります。しかし実際に入っているのは文字列なので、getFullYear() を呼んだ瞬間に落ちます。

見分け方: そのプロパティに対してメソッドを呼んでいる箇所を探します。日付の計算をしている場所が候補です。

直し方: 型は string のままにします。日付として扱いたい場所で、受け取ったあとに変換してください。

原因5: 型を書いたあとに API が変わった

型定義は、一度書くとそのまま残ります。一方で API は、項目が増えたり、値の形が変わったりします。

追加された項目は、型に無くても実害が出ません。困るのは消えた項目形が変わった項目で、どちらも実行時まで表面化しません。

見分け方: 型定義の更新日と、API の変更履歴を突き合わせます。履歴が無い場合は、実データから型を起こし直して差分を見ます。

直し方: 型を実データ起点で作り直す習慣にします。手で追記していくと、消えた項目がいつまでも残ります。

原因を絞る 3 つの手順

どれが原因か分からないときは、この順で進めると早く絞れます。

手順1: 実データを 3 件以上集める。開発環境のログでも、ブラウザの通信タブに出たレスポンスでもかまいません。1 件では原因1 と原因2 が見分けられません。

手順2: 実データから型を起こし直す。手で書くと、いま持っている思い込みがそのまま入ります。機械的に起こすほうが、思い込みの外にある差が出ます。

JSON→TypeScript型生成ツールに集めたレスポンスを続けて貼ってください。全件をまとめた型と、各項目が何件にあったかの表が出ます。桁が落ちた数値や、そのままでは書けないキーもその場で知らされます。

手順3: いま使っている型と見比べる。差が出た項目が原因の候補です。? の有無、| null の有無、numberstring かの 3 点を先に見てください。

型のずれを繰り返さないための線引き

原因を直したあと、同じことが起きないようにする方法は 2 つあります。

入口で 1 度だけ検査する。データが入ってくる場所、つまり通信の直後に検査を挟みます。ここを通ったあとは型を信じてよい、という線を引く考え方です。

型を実データから起こす習慣にする。手で書き足すのをやめ、レスポンスを貼って起こし直す形にします。項目が消えたことにも気づけます。

どちらも「型は実行時に何も守らない」という前提から出てきた対策です。守ってくれないなら、守る場所を自分で 1 箇所だけ作る、という発想になります。

まとめ

型定義と実データのずれは、5 つの原因にだいたい収まります。省略される項目、null と欠落の混同、大きな整数の桁落ち、日付の扱い、API の変更です。

どれも実行時まで表面化しないので、実データを集めて型を起こし直すのが一番早い切り分けになります。3 件並べれば、原因1 と原因2 はその場で見分けられます。

そのうえで、通信の直後に検査を 1 箇所だけ置いてください。型が守ってくれない範囲を、自分で線引きしておくのが確実です。

あわせて読みたい

同じテーマ・関連ツールの記事です。