Stop Hand-Writing TypeScript Interfaces for API Responses
Generate TypeScript interfaces from JSON automatically — faster and more accurate than hand-writing types for API responses.
Every frontend developer knows this ritual: you call a new API, get back a JSON blob with 40 fields, and then spend the next 20 minutes hand-writing an interface for it. Miss one nested object and TypeScript complains. Guess a field type wrong and you ship a bug.
There is a better way: infer the types straight from the JSON.
The problem with hand-written interfaces
Take a typical API response:
{
"id": 42,
"title": "Hello world",
"published": true,
"tags": ["webdev", "typescript"],
"author": {
"name": "Jane",
"followers": 1200
}
}
Hand-writing the interface is not hard — it is just tedious and error-prone:
interface Article {
id: number;
title: string;
published: boolean;
tags: string[];
author: Author;
}
interface Author {
name: string;
followers: number;
}
Now imagine that response has six levels of nesting, arrays of objects, and a few nullable fields. This is where hand-writing stops being "quick" and starts being a source of bugs.
Generate the types instead
The reliable approach is mechanical: parse the JSON, walk its structure recursively, and emit a type for every value.
string,number,booleanmap directlynullstaysnull- Arrays infer from their elements —
string[]for["a", "b"] - Arrays of objects get their own named interface, e.g.
ArticleItem - Mixed arrays become unions:
(number | string)[] - Empty arrays fall back to
any[]rather than guessing wrong
A free browser-based JSON to TypeScript converter does exactly this: paste the API response, name your root type, and copy the interfaces. It also handles the options you would otherwise set by hand — interface vs. type-alias style, optional properties, and the export keyword.
If you are working with a GraphQL codebase instead, the same idea applies: a JSON to GraphQL converter turns a sample payload into SDL type definitions, which is handy when sketching a schema from a REST response you are migrating.
Edge cases worth knowing
Nullable fields. JSON has null but no "optional" concept. If a field is null in your sample, mark it optional or widen it to string | null — whichever matches your API contract.
Inconsistent arrays. Real-world APIs sometimes return [1, "2"]. A union type (number | string)[] is honest; silently picking one type is not.
Root arrays. When the response itself is an array, you still want a named root: export type Root = Item[]; keeps imports clean.
Dates. JSON has no date type — "2026-09-26" is a string. If your codebase uses Date, do a second pass and swap those fields.
A workflow that actually sticks
- Hit the endpoint, copy the raw JSON response.
- Validate and format it first so you are converting clean data.
- Generate the TypeScript interfaces from the JSON.
- Review the output — rename the auto-generated nested types (
RootAuthor→Author) to match your domain language. - Paste into your project and let
tscdo the rest.
The review step matters. Generated types are a starting point, not a contract — your API's documentation (or its OpenAPI spec, if it has one) is the source of truth for which fields are truly optional.
Why this beats the alternatives
- Faster than hand-writing for anything beyond a flat object.
- More accurate — the machine reads the actual values, not your assumptions.
- Repeatable — when the API adds a field, regenerate instead of diffing by hand.
Next time you integrate an API, skip the manual interface. Generate it, review it, ship it.

