Generate TypeScript types from a REST API response

Every API you integrate means TypeScript interfaces to write and maintain. snaptype generates them automatically — from a live URL or a saved JSON file — in one command.

The problem

When you integrate a new REST API, you have two common options: cast the response to any and lose type safety entirely, or spend 20 minutes writing interfaces by hand — guessing which fields are optional, which strings are actually dates, and which values form an enum.

// Option A: give up on types
const data = await fetch("/api/users").then((r) => r.json()) as any;

// Option B: write by hand and hope you got it right
interface User {
  id: number;
  email: string;      // is this always a valid email?
  role: string;       // "admin" | "user"? who knows
  createdAt: string;  // a date? which format?
  deletedAt?: string; // nullable? optional? both?
}

Neither option scales. The manual interface drifts from the real API within a sprint, and any is a silent bug factory.

The solution

snaptype inspects the actual values in a JSON response — not just the structure — and infers the most precise types it can. Email strings become z.email(), ISO dates become z.iso.datetime(), and repeated string values with a small set of variants become union literals automatically.

How it works

Point snaptype directly at a live API endpoint:

npx snaptype from-url https://api.example.com/users -o src/types/user.ts

Or pass a saved JSON response file:

npx snaptype from-json api-response.json -o src/types/user.ts

Given a typical API response:

api-response.json
[
  {
    "id": 1,
    "email": "alice@example.com",
    "role": "admin",
    "createdAt": "2024-01-15T10:30:00.000Z"
  },
  {
    "id": 2,
    "email": "bob@example.com",
    "role": "user",
    "createdAt": "2024-03-22T08:00:00.000Z"
  },
  {
    "id": 3,
    "email": "carol@example.com",
    "role": "user",
    "createdAt": "2024-04-10T14:15:00.000Z"
  }
]

snaptype generates a TypeScript interface:

src/types/user.ts
export interface User {
  readonly id: number;
  email: string;           // email
  role: "admin" | "user";
  createdAt: string;       // ISO 8601
}

Add --zod for a runtime-validated schema alongside your interface:

src/types/user.ts
import { z } from "zod";

export const UserSchema = z.object({
  id: z.number(),
  email: z.email(),
  role: z.enum(["admin", "user"]),
  createdAt: z.iso.datetime(),
}).readonly();

export type User = z.infer<typeof UserSchema>;

What you get

Try snaptype in 30 seconds

No account needed. Works with any JSON file or API endpoint.

npm install -D snaptype
npx snaptype from-url https://api.example.com/users -o src/types/user.ts