# An API response to TypeScript

**An object with 2 nested shapes.**

## Input

```json
{
  "data": [
    { "id": "u_1", "email": "a@example.com", "verified": true },
    { "id": "u_2", "email": "b@example.com", "verified": false }
  ],
  "page": { "cursor": "abc", "hasMore": true, "total": 128 }
}
```

## TypeScript

```typescript
export interface Root {
  data: Data[];
  page: Page;
}

export interface Data {
  id: string;
  email: string;
  verified: boolean;
}

export interface Page {
  cursor: string;
  hasMore: boolean;
  total: number;
}
```

## Zod

```typescript
import { z } from 'zod';

export const PageSchema = z.object({
  cursor: z.string(),
  hasMore: z.boolean(),
  total: z.number(),
});

export const DataSchema = z.object({
  id: z.string(),
  email: z.string(),
  verified: z.boolean(),
});

export const RootSchema = z.object({
  data: z.array(DataSchema),
  page: PageSchema,
});
```

## Warnings

### Whole numbers are still `number` (info)

Every numeric value in the sample was a whole number, but JSON has a single number type and cannot express the difference. The output uses `number`.

**Fix:** If a field is genuinely an integer, tighten it by hand: `z.number().int()`.

---

Canonical URL: https://json-to-types.gumballtools.com/types/api-response-to-typescript
JSON API: `POST https://json-to-types.gumballtools.com/api/v1/convert`
MCP endpoint: `https://json-to-types.gumballtools.com/api/mcp`
