1. test 1
  2. test 2
  3. test 3
  4. test 4
コース一覧
TypeScript道場 fleama開発室の10問
APIレスポンスに型を通せ

TypeScript道場 fleama開発室の10問

TypeScript入門で身に付けた技を、商店街公式フリマアプリ「fleama」開発室の仕事で試す演習専用コースです。解説はありません。依頼と完成条件だけを読み、白紙から自分で組み立てます。手が止まったときのために、方針・使う構文・部分解の3段階のヒントを各問に用意しています。判定はコンパイラそのものです。型が通らないコードは実行される前に不合格になるので、まず tsc を黙らせてから中身を合わせることになります。基本型の注釈から始まり、関数の署名、any の撲滅、interface の設計、リテラルunion、型ガード、ジェネリクス、入口での変換、入れ子のAPIレスポンスを経て、最後は型のないモジュールを strict で通る形に組み直すところまで、10問で TypeScript の主要な道具を一巡します。1問10分から45分、全10問で約4.5時間です。TypeScript入門を終えて「読めるけれど自分では書けない」と感じている方に向いています。

1
初段
01. 赤い波線を消せ10分
02. 関数に正しい型を付けよ15分
03. このanyを撲滅せよ15分
04. Item型を設計せよ20分
2
中段
01. 不正な状態を型で封じよ25分
02. 型ガードで絞り込め25分
03. 汎用関数に型を付けよ30分
04. 型を付けて事故を防げ30分
3
師範
01. APIレスポンスに型を通せ35分
02. 総合 型のないモジュールを完全TS化45分

APIレスポンスに型を通せ

師範 / 目安 35分

凛さんが、fleama API のレスポンスを画面に貼りました。/items を叩くと、こういう形が返ってきます。

プレーンテキスト

{ "status": "ok", "data": { "total": 128, "items": [ { "id": 1, "name": "深煎りブレンド", "price": 480, "seller": { "id": 7, "name": "ハレノヒ珈琲" } } ] } }

「いま、これを受け取る変数の型は any です」と凛さん。「res.data.itms と打ち間違えても、誰も止めません。通信の向こう側は、型の空白地帯になっています」

通信の戻りは、確かに外の世界から来ます。しかし「何が返ってくるか分からない」のと「何が返ってくるか書いていない」のは別のことです。API の形は決まっています。決まっているものは書ける。書けば、その形からずれた読み方は全部コンパイラが弾いてくれます。

この形を型にするコツは、外側から内側へ、層ごとに分けることです。1つの巨大な interface に全部詰め込むと、読めないうえに再利用もできません。出品者は Seller、商品1件は Item、data の中身は ItemsData、いちばん外側が ItemsResponse です。Item の中に seller: Seller と書けば、入れ子はそのまま入れ子で表現できます。

凛さんが最後に釘を刺します。「as は使わないでください。as は『コンパイラより自分のほうが正しい』という宣言です。ときには必要ですが、形が分かっているレスポンスに使うのは、ただの手抜きです。型は宣言して通すもので、押し通すものではありません」

完成条件

この問題では通信そのものは行いません。レスポンスを引数で受け取った状態から始めます。

まず、上に貼ったレスポンスの形を4つの interface に分けて定義してください。

  • Seller — id (number) と name (string)
  • Item — id (number)、name (string)、price (number)、seller (Seller)
  • ItemsData — total (number) と items (Item[])
  • ItemsResponse — status (string) と data (ItemsData)

そのうえで pickItems という関数を定義してください。引数は ItemsResponse を1つだけ受け取り、次の形の文字列を返します。

プレーンテキスト

全128件中3件 / 深煎りブレンド(ハレノヒ珈琲) 480円, 抹茶ラテ(和菓子きくや) 580円

組み立ての決まりは次のとおりです。

  • 全 に total の値、件中 に 配列に入っている件数 を続け、件 で閉じます
  • 区切りは半角スペースを挟んだ / です
  • 商品1件は 商品名(出品者名) 価格円 の形にします。商品名と丸括弧のあいだにスペースは入れません
  • 商品どうしは , (カンマと半角スペース) でつなぎます
  • items が空のときは、うしろ側を 該当なし にします。例えば 全0件中0件 / 該当なし です

any と as は使わないでください。as を使っていないことは自動判定では測りませんが、凛さんの CI は人の目でも回っています。

進め方

白紙から書いてください。手が止まったらヒントを開けます。ヒントは3段階で、①方針、②使う構文、③部分解の順に出ます。1つも開けずに通せたら、その問題は自分のものです。

開かずに10分粘って進まないなら、①だけ開けてください。粘る時間そのものには価値がありません。価値があるのは、自分で書いた行が動いた瞬間です。

型を書き終えたら、response.data.items[0].seller.name まで補完が効くか確かめてください。エディタが最後まで案内してくれたら、型は通っています。

要件

  1. interface Seller を定義する。id(number) と name(string)
  2. interface Item を定義する。id(number)・name(string)・price(number)・seller(Seller)
  3. interface ItemsData を定義する。total(number) と items(Item[])
  4. interface ItemsResponse を定義する。status(string) と data(ItemsData)
  5. pickItems(response: ItemsResponse): string を定義する
  6. 件数の部分は「全○件中○件」の形。中の数は配列に入っている件数
  7. 商品1件は「商品名(出品者名) 価格円」の形で、商品どうしは「, 」でつなぐ
  8. items が空のときはうしろを「該当なし」にする
  9. any と as を使わないこと

入出力例

pickItems({"data":{"items":[{"id":1,"name":"深煎りブレンド","price":480,"seller":{"id":7,"name":"ハレノヒ珈琲"}},{"id":2,"name":"抹茶ラテ","price":580,"seller":{"id":9,"name":"和菓子きくや"}}],"total":128},"status":"ok"}) → "全128件中2件 / 深煎りブレンド(ハレノヒ珈琲) 480円, 抹茶ラテ(和菓子きくや) 580円" pickItems({"data":{"items":[{"id":42,"name":"自家製レモネード","price":560,"seller":{"id":7,"name":"ハレノヒ珈琲"}}],"total":1},"status":"ok"}) → "全1件中1件 / 自家製レモネード(ハレノヒ珈琲) 560円" pickItems({"data":{"items":[],"total":0},"status":"ok"}) → "全0件中0件 / 該当なし" pickItems({"data":{"items":[{"id":11,"name":"チーズケーキ","price":480,"seller":{"id":3,"name":"洋菓子ミモザ"}},{"id":12,"name":"季節のフルーツティー","price":620,"seller":{"id":7,"name":"ハレノヒ珈琲"}},{"id":13,"name":"カフェオレ","price":520,"seller":{"id":7,"name":"ハレノヒ珈琲"}}],"total":300},"status":"ok"}) → "全300件中3件 / チーズケーキ(洋菓子ミモザ) 480円, 季節のフルーツティー(ハレノヒ珈琲) 620円, カフェオレ(ハレノヒ珈琲) 520円"

ヒント

前のヒントを開くと次が開きます。開かずに解けると未開封クリアです

①方針 型はいちばん内側から書くと素直に積み上がります。Seller を書き、それを使って Item を書き、Item[] を持つ ItemsData を書き、最後に外側の ItemsResponse です。型が全部書けてから関数に手を付けてください。先に関数を書くと、途中で型を直すたびに書き直しになります

ヒント 2ヒント 1 を開くと読めます
ヒント 3ヒント 2 を開くと読めます
生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/09

関連レッスン

  • 総合 型のないモジュールを完全TS化

    型が一切ないモジュールを、strict で通る TypeScript に組み直します。問1から問9までの道具を総動員します。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • エンドポイント「この URL を叩くとこの機能が動く」入口の住所
  • APIアプリ間でデータをやり取りする窓口
  • リクエストWeb 通信の基本単位、ブラウザの問い合わせとサーバーの返答
  • 変数データに名前をつけて参照する仕組み
  • interface実装を持たないメソッド契約。複数 implements 可
  • 引数位置引数=順番で渡す。
  • 関数処理に名前を付けて再利用できる単位
  • 配列サイズ固定の同型データの集まり
main.ts
学習モード
エディタを読み込んでいます

メモ

APIレスポンスに型を通せ

⌘S で保存