Generate a TypeScript interface from JSON
Paste a sample object and get a ready TypeScript interface: in the example, id becomes number, tags becomes string[] and the key display-name is kept in quotes, all under the name UserRecord. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
The tool parses the sample, validates that its root is an object, and produces a deterministic interface for strings, numbers, booleans, null values, arrays, and nested objects.
How each type is worked out
The generator looks at every value in your sample, not at the names of the keys. Text becomes string, any number becomes number, true or false gets its own true-or-false type and an empty value becomes null. Objects inside objects turn into nested types, and lists are judged from all their elements, not just the first: a list of text alone is string[], while a mixed one gives a union such as (string | number | null)[]. Keys that cannot be written plainly, such as display-name, stay in quotes, and properties keep the order of the original sample.
Typical mistakes and how to avoid them
One sample cannot prove that a value is optional, so every property it contains is marked as required; adjust it by hand where your real data may leave something out. An empty list gives no evidence and becomes unknown[], and an empty object becomes Record<string, never>, so pick a sample whose lists and objects are filled in. The text must be strict data, not JavaScript: names need double quotes, comments and trailing commas are not allowed, and the top level must be an object. Dates, fixed values and enums are never invented.
Start from a sample that looks like your real data
Nested objects are represented as nested object types inside the root interface. Every property found in the sample is emitted as required because a single example cannot prove that a field is optional. For the most useful result, choose a sample that contains the fields and value variants your application really receives.
You may also provide a root interface name, such as <code>UserResponse</code>; it must be a valid, non-reserved TypeScript identifier. When omitted, the stable default is <code>RootObject</code>.
Understand arrays, nulls, and nested structures
Array inference considers every element in the sample rather than inspecting only the first. A list containing only strings becomes <code>string[]</code>, while a mixed list produces a stable union such as <code>(string | number | null)[]</code>. An empty array has no element evidence, so it becomes <code>unknown[]</code> instead of guessing a potentially misleading type.
Objects inside arrays are expressed as inline object types, and nested arrays are handled recursively. Empty objects become <code>Record<string, never></code>, which records that the sample exposed no known fields without pretending that arbitrary values were observed. The generator does not invent optional markers, date types, literal types, enums, or domain-specific class names because those conclusions cannot be established reliably from one sample.
FAQ
How are empty arrays typed?
They become unknown[] because an empty sample provides no evidence about its element type.
Are properties marked optional?
No. Properties present in the sample are required.
What kind of text can I paste?
Strict data text whose top level is an object. Names need double quotes, and comments or trailing commas are not allowed. A single value, a null or a list at the top level is refused, because the result describes an object.
Can I choose the name of the interface?
Yes. Enter a name such as UserRecord; it must be a valid TypeScript name that is not a reserved word. If you leave it empty, the interface is called RootObject, so repeated runs stay identical.
How is a list with mixed values typed?
Every element is checked, not only the first. A list of text alone becomes string[], while a mix produces a stable union such as (string | number | null)[], so the result reflects exactly what the sample shows.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev2/json-to-typescript-interface \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"json":"{\"id\":42,\"name\":\"Ada\",\"active\":true,\"tags\":[\"admin\",\"editor\"],\"profile\":{\"email\":\"ada@example.com\",\"score\":9.5}}"}'const res = await fetch("https://api.kit.forhosting.com/dev2/json-to-typescript-interface", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"json": "{\"id\":42,\"name\":\"Ada\",\"active\":true,\"tags\":[\"admin\",\"editor\"],\"profile\":{\"email\":\"ada@example.com\",\"score\":9.5}}"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev2/json-to-typescript-interface",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"json": "{\"id\":42,\"name\":\"Ada\",\"active\":true,\"tags\":[\"admin\",\"editor\"],\"profile\":{\"email\":\"ada@example.com\",\"score\":9.5}}"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev2/json-to-typescript-interface", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"json":"{\\"id\\":42,\\"name\\":\\"Ada\\",\\"active\\":true,\\"tags\\":[\\"admin\\",\\"editor\\"],\\"profile\\":{\\"email\\":\\"ada@example.com\\",\\"score\\":9.5}}"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"json":"{\"id\":42,\"name\":\"Ada\",\"active\":true,\"tags\":[\"admin\",\"editor\"],\"profile\":{\"email\":\"ada@example.com\",\"score\":9.5}}"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev2/json-to-typescript-interface", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"json": "{\"id\":42,\"name\":\"Ada\",\"active\":true,\"tags\":[\"admin\",\"editor\"],\"profile\":{\"email\":\"ada@example.com\",\"score\":9.5}}"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev2.json_to_typescript_interface",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_chars | 1000000 |
max_depth | 64 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Turn a representative JSON object into a TypeScript interface without installing a generator or manually tracing every nested value. It also protects unusual JSON keys with quoted property names and lets you choose the root interface name.
Start with a representative JSON object
Paste valid JSON whose root value is an object, such as an API response, configuration record, webhook payload, or stored document. The generator examines values rather than relying on field names, so a string becomes <code>string</code>, any JSON number becomes <code>number</code>, a Boolean becomes <code>boolean</code>, and a null value becomes <code>null</code>. The input must be JSON text, not JavaScript object syntax: property names require double quotes, comments are not allowed, and trailing commas are invalid. A scalar, null, or array at the root is rejected because the requested output is specifically an interface describing a JSON object.
Understand arrays, nulls, and nested structures
This makes the output honest about the evidence in the supplied JSON. Property order follows the original JSON object, while union members use a deterministic order so repeated runs produce identical text. JSON keys that cannot safely appear as ordinary TypeScript property identifiers, including keys with spaces, punctuation, or reserved words, are emitted as quoted string properties.
Review the generated interface before production use
If one sample contains null and another contains a string, combine that knowledge in your maintained type. The deterministic output is especially useful in code review because the same input and interface name always yield the same result, with no network calls, model variability, random values, or timestamps. Keep sensitive examples out of tickets or shared logs even though generation itself needs no third-party service. Treat the generated definition as an accurate description of the supplied example and a strong first draft for real application code, not as proof of an external API contract. Compare it with several payloads or the provider's documentation before deciding whether properties should be optional, nullable, narrower, or shared through named interfaces. For example, a timestamp remains a string because JSON has no date type, and an integer remains <code>number</code> because TypeScript does not distinguish JSON integers at runtime. Invalid JSON, missing JSON text, invalid interface names, excessive nesting, and non-object roots return an <code>invalid_input</code> error rather than partial code. API execution starts at $0.002 per request, while the browser version can apply the same pure inference logic locally.
Integration use cases
Type an unfamiliar API response
Create a practical first interface from a captured response before refining optional fields against the API documentation.
Document webhook payloads
Convert a representative event object into readable TypeScript that a receiving service and its tests can share.
Bootstrap fixtures and integrations
Generate stable nested types for configuration, imported records, or test data without tracing each property manually.
Technical questions
What inputs are accepted?
The json field must contain valid JSON text whose root value is an object. Root arrays, scalars, and null are rejected.
Does it recognize dates or enums?
No. JSON strings remain string values, and the generator does not infer domain semantics or enum constraints from one example.
How much does an API request cost?
An API request starts at $0.002. The browser runner uses the same deterministic inference logic.