レスポンスに型を付ける

json() が返すものには型が無い

前回のコードには穴があります。

const data = await res.json(); setItems(data);

res.json() が返すのは any です。中身が何かは、返ってくるまで誰にも分からないからです。any は「何でもあり」という意味なので、そのまま setItems に渡せてしまいます。仮に API が数字の配列を返しても、文字を返しても、その場では何も言われません。型検査をすり抜ける穴がここに空いています。

as で塞ぐのはごまかし

塞ぎ方として、まずこれを思いつきます。

const data = (await res.json()) as Item[];

as は「これは Item の配列だと思ってくれ」という宣言です。TypeScript は確かめずに信じます。中身が違っても黙って通るので、穴の場所を変えただけです。事故は使う場所まで先送りされます。

取得関数の戻り値に型を書く

まともなやり方は、取ってくる仕事を関数に切り出して、その関数が何を返すかを書くことです。

async function fetchItems(): Promise<Item[]> { const res = await fetch("/api/items"); const data: Item[] = await res.json(); return data; }

async の付いた関数は必ず Promise を返します。だから戻り値の型は Item[] ではなく Promise<Item[]> と書きます。TypeScript入門で出てきた「入れ物の型」です。

こう書くと、呼ぶ側では await fetchItems() の結果がそのまま Item[] になります。

const list = await fetchItems();

listItem[] です。list[0].titel と打ち間違えれば、その場で赤い線が出ます。

境界を1か所にまとめる

大事なのは、外から来たものを型のある世界に入れる場所を1か所にすることです。fetchItems の中だけが API の形を知っていればよく、それ以外の場所は Item[] としか付き合いません。API の返す形が変わっても、直すのはこの関数だけになります。

演習

取得を fetchItems という関数に切り出し、戻り値に型を付けます。

ヒント

App.tsx
mock-api.json
App.tsx
mock-api.json
プレビュー

できているか

  • カードが5枚並んでいる
  • API の商品が出ている