What this tool does
A JSON sample becomes io-ts codecs, one const per object.
{ "id": 1, "name": "Ada", "address": { "city": "Paris" } }
import * as t from "io-ts";
export const Address = t.type({
city: t.string,
});
export const Root = t.type({
id: t.Int,
name: t.string,
address: Address,
});
Children are declared first: codecs are runtime values, so one has to exist before another mentions it. An array at the root gets its own codec — export const Users = t.array(UsersItem); — rather than leaving you to write it.
t.Int is branded, and that shows
t.Int is a refinement of t.number carrying a proof of integrality. t.TypeOf<typeof Root> therefore gives { id: Int; … }, not { id: number; … }. An Int goes wherever a number is expected; the reverse needs a decode. If that friction is not worth an integer check in your codebase, t.number is a one-word replacement.
Which of the two you get depends on how the number was written: 3 gives t.Int, 10.0 gives t.number. Until recently 10.0 also gave t.Int, and the codec then rejected 10.5 — the next record. That was a real defect, found while writing these pages and fixed.
What a codec lets through
t.type checks what it knows and ignores the rest. A response with three extra fields decodes cleanly. That is io-ts’s interface semantics, and it is the right default for reading someone else’s API — but if an unexpected key should be an error, wrap the same shape in t.strict, or t.exact to strip it.
Decoding, in one line
import { isRight } from "fp-ts/Either";
const result = Root.decode(payload);
if (isRight(result)) { /* result.right is typed */ }
PathReporter.report(result) turns a failure into readable paths — worth having on hand the first time a codec refuses a payload you thought was fine.
Everything is required
Every key from the sample lands in t.type, which means required. io-ts writes optionality as a separate t.partial, joined with t.intersection. Splitting your keys between the two halves is a statement about the API; one document cannot make it for you.
Private by design
Everything runs locally in your browser with JavaScript. Your data is never uploaded, which makes the tool safe for sensitive content, and it keeps working offline.