{ } Schemato

Guide

Convert an OpenAPI spec into TypeScript types — without a generator

Most front-end projects don't need a full OpenAPI client. They need three or four types. Here's the lighter path.

Need it now? OpenAPI → TypeScript converter.


Step 1 — Find the schema you actually need

Most teams discover later they only really cared about a handful of types. Open the spec and copy just the relevant chunk:

openapi: 3.0.3
info:
  title: Demo
  version: 1.0.0
paths: {}
components:
  schemas:
    User:
      type: object
      required: [id, name]
      properties:
        id: { type: integer }
        name: { type: string }
        email: { type: string, format: email }
        addresses:
          type: array
          items: { $ref: "#/components/schemas/Address" }
    Address:
      type: object
      required: [line1, country]
      properties:
        line1: { type: string }
        city: { type: string }
        country: { type: string }

Step 2 — Generate TypeScript interfaces

Paste the spec (JSON or YAML) into the OpenAPI → TypeScript converter. You'll get one named interface per components.schemas entry, with $ref turned into proper type references:

export interface Address {
  "line1": string;
  "city"?: string;
  "country": string;
}

export interface User {
  "id": number;
  "name": string;
  "email"?: string;
  "addresses"?: Address[];
}

Step 3 — Use the types in fetch

Annotate the return type so your IDE flags any field-level drift the moment the backend changes:

import type { User } from "./types";

export async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json() as Promise<User>;
}

Step 4 — Wire into React Query / SWR

Pass the generated type as the query result type. data is now fully typed throughout your component tree:

import { useQuery } from "@tanstack/react-query";
import type { User } from "./types";

export function useUser(id: number) {
  return useQuery<User>({
    queryKey: ["user", id],
    queryFn: () => fetch(`/api/users/${id}`).then((r) => r.json()),
  });
}

Step 5 — Decide if you want runtime validation

TypeScript types disappear at runtime. If you want to fail fast when the backend ships an unexpected shape (especially in B2B integrations), pair the types with a Zod schema:

// Want runtime validation as well? Convert the same schema to Zod
// instead — see /guides/json-to-zod and /openapi-to-zod.
import { User } from "./schemas";
const u = User.parse(await fetch("/api/me").then(r => r.json()));

Schemato has OpenAPI → Zod for that. Use whichever fits your trust model.


Common pitfalls

FAQ

Why not just use openapi-typescript or orval?

Both are great for full clients. This is a lighter path: one paste, no install, no codegen step in CI.

Does the converter understand $ref?

Yes — same-document $ref into components.schemas becomes named interfaces.

JSON or YAML?

Both. Schemato includes a lightweight YAML parser sufficient for the OpenAPI subset.

Does this generate API client wrappers?

No — only types. Use openapi-fetch if you need wrappers; often raw fetch is enough.

Related