Type a Full API Response JSON as TypeScript

Learn how to convert a complete REST API response including metadata, pagination, and nested data into a set of TypeScript interfaces.

Advanced Patterns

Detailed Explanation

Typing a Real API Response

Production API responses include more than just the data payload. They contain metadata, pagination info, error fields, and deeply nested objects. Converting the full response into TypeScript types requires a systematic approach.

Example JSON

{
  "status": "success",
  "data": {
    "users": [
      {
        "id": 1,
        "name": "Alice",
        "email": "alice@example.com",
        "profile": {
          "avatar": "https://cdn.example.com/alice.jpg",
          "bio": "Full-stack developer"
        }
      }
    ],
    "pagination": {
      "page": 1,
      "perPage": 20,
      "total": 150,
      "totalPages": 8
    }
  },
  "requestId": "req_abc123"
}

Generated TypeScript

interface Profile {
  avatar: string;
  bio: string;
}

interface User {
  id: number;
  name: string;
  email: string;
  profile: Profile;
}

interface Pagination {
  page: number;
  perPage: number;
  total: number;
  totalPages: number;
}

interface ApiResponse {
  status: string;
  data: {
    users: User[];
    pagination: Pagination;
  };
  requestId: string;
}

Structuring the Types

  1. Start from the leaves — Define the innermost types first (Profile, then User).
  2. Extract reusable typesPagination will appear in many list endpoints; define it once.
  3. Narrow the status field — Change status: string to status: "success" | "error" for better type safety.
  4. Add error shape — API responses often have different shapes for success and error. Use a discriminated union to handle both.

Making It Generic

For APIs that return paginated lists of different resources, create a generic wrapper:

interface PaginatedResponse<T> {
  status: "success";
  data: {
    items: T[];
    pagination: Pagination;
  };
  requestId: string;
}

// Usage
type UserListResponse = PaginatedResponse<User>;

This avoids duplicating the envelope structure for every endpoint.

Use Case

You are building a frontend client library for your REST API and need complete TypeScript coverage of every response shape to enable end-to-end type safety with fetch wrappers.

Try It — JSON to TypeScript

Open full tool