# From API response to types: TS interface, Go struct, PHP class

> Generate TypeScript, Go struct, PHP class from JSON online. Automatic type inference with nested objects, array element, optional/nullable detection.

Free in-browser tool (no upload): https://www.mauriziofonte.it/tools/json-to-typescript-go-php

From a sample JSON payload, generate **type definitions** for TypeScript (interface), Go (struct with json tags) and PHP (class with typed readonly properties and constructor promotion). Automatic type inference for primitives, nested objects and arrays (element type inferred from the first element). Built to model API responses in typed clients without hand-writing them: paste the real payload an API returns, pick the target language, get the matching type definitions.

## How to use the generator

1. **Paste the JSON** - Enter a representative JSON payload. Ideally: a response from a real endpoint, not a mock. Type inference works best with real data (it captures nullability, optionals, array element shape).
2. **Set the root type name** - Default 'Root'. Change it to a semantic name (e.g. 'UserResponse', 'OrderEvent', 'WebhookPayload'). The name is used as prefix for nested types (e.g. UserAddress, UserOrders).
3. **Generate the types** - 'Generate' button: produces 3 parallel outputs (TS interface, Go struct, PHP class) all based on the same type inference. The top tabs switch between them.
4. **Copy into your project** - The Copy button copies the active tab. Paste into a.ts /.go /.php file in your project. Manual adjustments (jsdoc, validation, default values) come afterwards.

## Why a multi-target type generator

**Type-first development.** Modern APIs emit JSON, but modern clients (TS, Go, PHP 8+) prefer static types. Hand-writing interfaces for each payload is tedious and error-prone. An automatic generator takes a sample JSON and produces ready-to-use types, cutting time-to-first-call from minutes to seconds.

**Multi-target rationale.** Three targets cover 90% of modern backend stacks: TypeScript (Vue/React/Angular frontends + Node backends), Go (cloud-native microservices), PHP 8.x (Laravel/Symfony). Generating all three from a single input is useful in heterogeneous teams where the same API serves different clients.

**Heuristic type inference.** Types inferred from the first value seen. Limitations: mixed arrays (e.g. `[1, "two", true]`) typed as union/any/mixed; null as optional; integer-only numbers become `int`/`number`, float-only become `float`/`number`; mixed integer+float become `float`. For more complex cases (oneOf, discriminated unions) define types manually starting from the generated output.

## Glossary

- **Type inference**: Automatic process of deriving types from sample data. Distinct from type checking (static verification): here inference produces a type definition starting from a concrete sample.
- **Discriminated union**: Pattern where a type has variants distinguished by a discriminator field (e.g. `{type: "a", a_field:...}` vs `{type: "b", b_field:...}`). Not handled automatically by inference from a single sample (requires multi-sample analysis).
- **Constructor promotion (PHP 8)**: PHP 8.0+ syntax that allows declaring and assigning properties in the constructor with inline visibility: `public function __construct(public string $name, public int $age)`. Used in the generated PHP types to reduce boilerplate.
- **Struct tag (Go)**: Metadata string attached to a struct field, read via reflection. `json:"field_name"` serves encoding/json for field  JSON key mapping. The generator emits the json tag automatically based on the original key.
- **Readonly properties (PHP 8.1+)**: `readonly` modifier that makes a property immutable after init in the constructor. Best practice for DTOs / value objects derived from immutable JSON. The generator emits readonly by default.
- **Optional vs nullable**: TypeScript: `field?: T` (may be missing) vs `field: T | null` (present but null). They are distinct. The generator emits `field?: T | null` when the sample shows `null` (both possibilities).

## Frequently asked questions

### Can I use the generator with any JSON?

Yes, it accepts any valid JSON. Practical limit ~5MB of input (above that the browser may slow down). For top-level arrays, the generator infers the element type and produces `type Root = ElementType[]`.

### Is type inference deterministic?

Yes. The same input JSON always produces the same output. The choices are based solely on the sample, not probabilistic heuristics. Limit: mixed arrays produce union/any/mixed, this is the deliberate choice.

### How are nested type names generated?

PascalCase of the field key, prefixed with the root name. Example: root `User` with field `address.street` -> type `UserAddress` with field `street`. For arrays of objects: `orders[0].items` -> `UserOrdersItems`. Any collisions (two paths producing the same name) are NOT resolved automatically: rename manually.

### Does it always produce valid Go?

Yes, field names are PascalCased (Go requires capital for export), json tags retain the original key, types match those compatible with encoding/json. For Go optionals it uses `*T` + `omitempty` tag (idiomatic Go).

### Which PHP version does the output target?

PHP 8.1+ syntax: typed properties, readonly, constructor promotion. To support PHP 7.4 take the output and change `public readonly Type $field` to `private Type $field` + getter. PHP 8.0 (no readonly) is a trivial fix: remove `readonly`.

### Can I also generate from YAML?

No, JSON only. For YAML, first convert it to JSON with the [YAML/JSON/TOML converter](/tools/yaml-json-converter) on this site, then paste the JSON here.

### Does it also generate JSON Schema or OpenAPI?

No, scope is deliberately limited to language-static types. JSON Schema and OpenAPI require specialized tooling that handles constraints (required, enum, pattern, format), oneOf/anyOf, external references: use a dedicated OpenAPI editor or a commercial multi-target generator.

---
Tool by Maurizio Fonte, senior backend engineer. All tools: https://www.mauriziofonte.it/tools/
