JSONエンベロープから汎用TypeScriptラッパー型を作成する

ページネーションやAPIラッパーなどの繰り返しJSONエンベロープパターンを再利用可能なジェネリックTypeScript型に変換する方法を学びます。

Complex Types

詳細な説明

JSONパターンからのジェネリックラッパー

多くのAPIはデータを一貫したエンベロープでラップします:ステータスフィールド、ページネーションメタデータ、そして実際のペイロード。すべてのエンドポイントでこの構造を複製する代わりに、ジェネリックラッパー型を作成できます。

JSON例(ユーザーエンドポイント)

{
  "ok": true,
  "data": [{ "id": 1, "name": "Alice" }],
  "meta": { "page": 1, "total": 50, "perPage": 10 }
}

JSON例(商品エンドポイント)

{
  "ok": true,
  "data": [{ "sku": "ABC-123", "price": 29.99 }],
  "meta": { "page": 1, "total": 200, "perPage": 10 }
}

生成されるTypeScript

interface Meta {
  page: number;
  total: number;
  perPage: number;
}

interface ApiListResponse<T> {
  ok: boolean;
  data: T[];
  meta: Meta;
}

interface User {
  id: number;
  name: string;
}

interface Product {
  sku: string;
  price: number;
}

type UserListResponse = ApiListResponse<User>;
type ProductListResponse = ApiListResponse<Product>;

ジェネリックパターンの検出

コンバーターは以下の場合にジェネリックラッパーを識別します:

  1. 複数のレスポンスが同一の外部構造(非データフィールドで同じキーと型)を共有する。
  2. データフィールドが変化する — レスポンス間で異なる内部オブジェクト。
  3. エンベロープキー(okmetaerror)が一貫している。

単一アイテムラッパー

リストではなく1つのアイテムを返す詳細エンドポイント用:

interface ApiDetailResponse<T> {
  ok: boolean;
  data: T;
  meta?: never; // 明示的に存在しない
}

type UserDetailResponse = ApiDetailResponse<User>;

エラーエンベロープ

interface ApiErrorResponse {
  ok: false;
  error: {
    code: string;
    message: string;
  };
}

type ApiResponse<T> = ApiListResponse<T> | ApiErrorResponse;

メリット

  • 単一の真実の源 — エンベロープ構造の変更(例:requestIdの追加)はジェネリックinterfaceの更新のみで済みます。
  • 型安全性UserListResponsedataProduct[]ではなくUser[]を含むことを保証します。
  • ボイラープレートの削減 — エンドポイントは同じラッパーを再利用し、API多用のコードベースでinterface数を50%以上削減できます。

ユースケース

APIがすべてのレスポンスをok、data、metaフィールドを含む同じエンベロープ構造で返し、ラッパーを50回複製する代わりにすべてのエンドポイントで機能するジェネリック型が必要な場合に使用します。

試してみる — JSON to TypeScript

フルツールを開く