JSON Schema a TypeScript
Genera definiciones TypeScript desde JSON Schema para contratos API fuertemente tipados
Converting JSON Schema to TypeScript: From Schema Definitions to Type-Safe Code
JSON Schema provides a declarative vocabulary for describing the structure, constraints, and validation rules of JSON data. When building TypeScript applications that consume schema-defined APIs, databases, or configuration formats, translating those schema definitions into TypeScript interfaces by hand is repetitive and error-prone. This tool automates that translation β it reads a JSON Schema document and produces TypeScript interfaces and type aliases that precisely reflect the schema's type constraints, required properties, nullable fields, enumerations, and composition patterns. The generated types enforce schema compliance at compile time, catching data shape mismatches before runtime while preserving the full expressiveness of JSON Schema's type system.
Schema Type Mapping: JSON Schema Types to TypeScript Equivalents
JSON Schema defines a fixed set of primitive types that map directly to TypeScript's type system. The converter applies these mappings consistently across every property and nested schema it encounters:
stringβstring: String schemas map directly. Format keywords like"format": "email"or"format": "uri"are preserved as documentation comments but do not alter the TypeScript type, since TypeScript lacks built-in format validation.numberandintegerβnumber: Both numeric schema types map to TypeScript's singlenumbertype. While JSON Schema distinguishes integers from floating-point numbers for validation, TypeScript has no separate integer type at the type level.booleanβboolean: A direct one-to-one mapping with no ambiguity.nullβnull: Explicit null types in the schema generate thenullliteral type. When combined with other types via array syntax (e.g.,"type": ["string", "null"]), the converter produces a union:string | null.objectβ interface or inline type: Object schemas with definedpropertiesgenerate structured interface bodies. Objects without properties but withadditionalPropertiesproduce index signatures likeRecord<string, unknown>.arrayβ typed arrays or tuples: Array schemas with a singleitemsschema produceT[]syntax. Tuple validation using arrayitemsgenerates TypeScript tuple types like[string, number].
Nullable types deserve special attention: JSON Schema expresses nullability through the type
array pattern "type": ["string", "null"]. The converter recognizes this and
generates string | null β a union type that explicitly communicates the null
possibility to TypeScript's strict null checking system.
Composition Keywords: allOf, anyOf, oneOf, and $ref
JSON Schema's composition keywords allow building complex types from simpler schemas. Each keyword maps to a specific TypeScript pattern:
allOfβ intersection types (&): When a schema usesallOfto combine multiple sub-schemas, the converter produces an intersection type. This models the "must satisfy all constraints" semantic β the resulting TypeScript type requires all properties from every sub-schema to be present.anyOfβ union types (|): TheanyOfkeyword means "valid against at least one sub-schema." The converter generates a union type, allowing the value to conform to any of the listed type shapes. TypeScript's type narrowing and discriminated unions work naturally with this output.oneOfβ union types (|): Semantically,oneOfmeans "valid against exactly one sub-schema" β a more restrictive condition thananyOf. However, TypeScript's type system cannot express exclusivity, so the converter generates a union type (same asanyOf), relying on runtime validation for the exclusivity constraint.$refβ resolved references: Schema references using$refpointers (e.g.,"$ref": "#/$defs/Address") are resolved by following the JSON Pointer path within the document. The referenced schema is then converted as if inlined at the reference point, producing the appropriate TypeScript type.
The $defs (or legacy definitions) section serves as a library of
reusable schemas within a document. When multiple properties reference the same definition,
the converter resolves each reference independently, producing consistent types throughout
the generated output. This keeps the conversion stateless per-property while maintaining
correctness across the entire schema document.
Enumerations and Constant Values: Literal Types in TypeScript
JSON Schema provides two keywords for restricting values to specific constants: enum
for a set of allowed values, and const for a single fixed value. Both map
elegantly to TypeScript's literal type system:
enumβ union of literals: A schema like"enum": ["draft", "published", "archived"]generates the type"draft" | "published" | "archived". This gives TypeScript exhaustiveness checking in switch statements and prevents assignment of invalid string values at compile time.constβ single literal type: A schema with"const": "active"produces the type"active"β a type that accepts only that exact value. This is useful for discriminator properties in tagged unions.- Mixed enum types: JSON Schema allows enums with mixed types:
"enum": [1, 2, "custom", null]. The converter produces the corresponding union of literals:1 | 2 | "custom" | null, preserving the exact allowed values regardless of their JSON types. - Numeric enums: Enumerations containing only numbers (e.g., status codes like
"enum": [200, 201, 204, 404]) generate numeric literal unions:200 | 201 | 204 | 404. These provide the same compile-time safety as string enums while being suitable for numeric domains.
The literal type approach is preferred over TypeScript's enum keyword because
JSON Schema enums are unordered value sets, not named constants. Union literals align more
naturally with the schema's intent and avoid the runtime code generation that TypeScript
enums introduce. They also compose cleanly with other union types in the surrounding schema.
Required vs. Optional Properties and additionalProperties
JSON Schema distinguishes between required and optional properties through the required
array at the object level. The converter translates this distinction directly into TypeScript's
optional property syntax:
- Required properties: Properties listed in the
requiredarray generate standard property declarations:name: string;. The absence of the?modifier tells TypeScript that this property must always be present. - Optional properties: Properties defined in
propertiesbut not listed inrequiredgenerate optional declarations:nickname?: string;. This allows the property to be absent from conforming objects without triggering type errors. additionalProperties: true: When the schema allows arbitrary additional properties, the converter appends an index signature:[key: string]: unknown;. This permits any string-keyed property while maintaining type safety for declared properties.additionalPropertieswith a schema: When additional properties are constrained to a specific type (e.g.,"additionalProperties": {"type": "string"}), the converter generates a typed index signature:[key: string]: string;. This models dictionary-like objects where all dynamic keys share a value type.
The interaction between required and properties is the primary
mechanism for expressing optionality in JSON Schema. Unlike the sibling JSON-to-TypeScript
tool which must infer optionality from sample data (marking properties absent from
some array elements as optional), this tool reads optionality explicitly from the
schema's required array β producing more accurate and intentional type definitions.
Practical Applications: API Contracts, Code Generation, and Validation
Converting JSON Schema to TypeScript bridges the gap between API specification and implementation. Key use cases where this workflow adds value:
- OpenAPI/Swagger integration: OpenAPI specifications define request and response bodies using JSON Schema. Extracting those schemas and converting them to TypeScript provides type-safe API clients without relying on full code generation toolchains like openapi-generator.
- Form validation alignment: Libraries like Ajv validate data against JSON Schema at runtime. Generating TypeScript types from the same schema ensures that your compile-time types and runtime validation logic always agree β eliminating the common bug where types and validators drift apart.
- Configuration schemas: Tools like VS Code extensions, ESLint plugins, and package.json define their configuration through JSON Schema. Converting those schemas to TypeScript gives you autocompletion and type checking when programmatically reading or writing configuration values.
- Event-driven architectures: Message brokers (Kafka, RabbitMQ, EventBridge) often use JSON Schema for event contracts. Generating TypeScript types from event schemas ensures producers and consumers agree on payload shapes, catching contract violations at build time rather than in production.
- Database document schemas: Document databases like MongoDB support JSON Schema validation on collections. Generating TypeScript interfaces from those collection schemas keeps your application code in sync with database-level constraints.
In each scenario, the JSON Schema serves as the single source of truth for data structure, and the generated TypeScript types become a derived artifact that stays synchronized with the schema as it evolves β eliminating manual transcription and the inconsistencies it introduces.
Code Examples
JSON Schema with nested objects, enums, and nullable types converted to TypeScript
{
"title": "UserProfile",
"type": "object",
"required": ["id", "username", "role"],
"properties": {
"id": { "type": "integer" },
"username": { "type": "string" },
"email": { "type": ["string", "null"] },
"role": {
"enum": ["admin", "editor", "viewer"]
},
"preferences": {
"type": "object",
"properties": {
"theme": { "type": "string" },
"language": { "type": "string" }
}
},
"tags": {
"type": "array",
"items": { "type": "string" }
}
}
}Output:
interface UserProfile {
id: number;
username: string;
email?: string | null;
role: "admin" | "editor" | "viewer";
preferences?: {
theme?: string;
language?: string;
};
tags?: string[];
}Schema composition with allOf and $ref definitions
{
"title": "Employee",
"$defs": {
"Address": {
"type": "object",
"required": ["street", "city"],
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zipCode": { "type": "string" }
}
}
},
"allOf": [
{
"type": "object",
"required": ["name"],
"properties": {
"name": { "type": "string" },
"department": { "type": "string" }
}
},
{
"type": "object",
"properties": {
"address": { "$ref": "#/$defs/Address" }
}
}
]
}Output:
type Employee = {
name: string;
department?: string;
} & {
address?: {
street: string;
city: string;
zipCode?: string;
};
};Standards & Specifications
- JSON Schema Specification (2020-12) β The official JSON Schema specification defining vocabulary for structural validation of JSON documents β the input format this tool processes
- TypeScript Handbook β Object Types β Official documentation on TypeScript interfaces, optional properties, and index signatures β the output format this tool generates
- JSON Pointer (RFC 6901) β Defines the pointer syntax used in $ref resolution within JSON Schema documents (e.g., #/$defs/Address)
Preguntas Frecuentes
What does JSON Schema to TypeScript generate?
It turns a JSON Schema into TypeScript declarations so you can use the schema as type-safe interfaces or type aliases in your codebase.
Does it preserve enums, required fields, and nested objects?
Yes. The generated output keeps schema structure, required properties, enums, and nested definitions in the emitted TypeScript.
Can I choose the generated type name?
Yes. You can provide a custom interface name, or let the tool derive one from the schema title when available.
Why use this instead of hand-writing types?
Because schemas drift less than human memory. Generate from the source of truth, then refine only where necessary.
Does the generated code run in my browser only?
Yes. The conversion is local, so your schema never leaves the device and you avoid the delightful industry sport of accidental data exposure.