JSON a TypeScript
Incolla JSON e ottieni all'istante interfacce TypeScript.
Come usare
- Incolla il tuo JSON nel pannello di sinistra (oggetto o array).
- Clicca su Converti · le interfacce TypeScript appaiono a destra.
- Regola il nome radice e attiva le opzioni in base alle tue esigenze.
- Clicca su Copia l'output per copiare il codice generato.
Domande frequenti
Gestisce gli oggetti annidati?
Sì. Ogni oggetto annidato riceve la propria interfaccia con nome. Anche gli elementi degli array vengono analizzati per determinare il tipo di elemento.
Cosa succede con array di tipi misti?
Se un array contiene elementi di tipi diversi, il convertitore usa un tipo unione (per es. string | number).
Supporta gli array JSON alla radice?
Sì. Se il valore radice è un array, il convertitore analizza i suoi elementi e produce l'interfaccia appropriata insieme a un alias di tipo per l'array.
Cosa fa effettivamente il convertitore
Analizza il JSON, percorre ogni valore e genera un insieme di dichiarazioni interface TypeScript che descrivono la struttura. Ogni oggetto nidificato ottiene una propria interface con nome, derivata dalla chiave della proprietà padre in PascalCase (un campo user diventa una User interface). Quando due oggetti nidificati collidono sul nome, al secondo viene aggiunto un suffisso numerico (User, User2). A livello radice, un array diventa un alias type Root = RootItem[]; più la RootItem interface; un oggetto diventa una singola Root interface (o qualunque nome si inserisca nel campo «root name»).
Esempio di input e output:
// Input
{
"id": 42,
"name": "Ada",
"active": true,
"tags": ["admin", "billing"],
"profile": { "bio": "Programmer", "link": null }
}
// Output
export interface Root {
id: number;
name: string;
active: boolean;
tags: string[];
profile: Profile;
}
export interface Profile {
bio: string;
link: unknown;
}
Il mapping dei tipi JSON → TypeScript
| Valore JSON | TS generato |
|---|---|
"hello" | string |
42 o 3.14 | number (TS non ha un tipo intero separato) |
true / false | boolean |
null | unknown (il convertitore non riesce a stabilire se il campo è nullable o semplicemente assente in questo campione) |
[] | unknown[] |
[1, 2, 3] | number[] |
[1, "x"] | (number | string)[] |
{ "a": 1 } | interface denominata |
Per gli array di oggetti a livello radice, il convertitore unisce le chiavi di tutti gli elementi in un'unica interface rappresentativa. È un'approssimazione ragionevole quando gli elementi condividono la stessa struttura, ma perde informazioni quando le strutture divergono davvero (ad es. un array di eventi eterogenei). In quel caso, sarà necessario scrivere a mano un'unione discriminata dopo la generazione.
Perché interface per gli oggetti e type per l'array radice
Il TypeScript Handbook ufficiale fornisce un'euristica in una riga: «Se volete un'euristica, usate interface finché non avete bisogno di usare funzionalità di type.» Entrambi sono strutturalmente tipizzati, entrambi possono descrivere strutture di oggetti, ma interface prevale per le strutture degli oggetti perché supporta il declaration merging (riaprire l'interface per aggiungere campi), funziona bene con extends e appare per nome negli errori del compilatore. Gli alias type sono necessari per le unioni di primitivi, le intersezioni di più tipi o per denominare qualcosa che non è un oggetto: ecco perché l'array a livello radice ottiene un alias type Root = RootItem[]; anziché un'interface.
Una nota sulla denominazione: il convertitore usa il PascalCase senza il prefisso I storico (quindi User anziché IUser). Le linee guida di stile TypeScript moderne (quelle di Google, Microsoft e della comunità React) quasi universalmente eliminano il prefisso. I nomi delle proprietà corrispondono esattamente alle chiavi JSON (camelCase se il JSON usa camelCase, snake_case se usa snake_case). Le chiavi che non sono identificatori JS validi (contenenti trattini, spazi o che iniziano con una cifra) vengono messe tra virgolette: "foo-bar": string;.
Cosa non fa questo strumento (ammettere i limiti)
Un singolo esempio JSON contiene meno informazioni di uno schema reale, quindi alcune cose che sarebbe utile rilevare non sono possibili dal solo input:
- Campi opzionali. Ogni proprietà dell'esempio diventa obbligatoria. Se la vera API a volte omette un campo, è necessario aggiungere
?a mano:email?: string;. In alternativa, eseguire il convertitore su più esempi e unire i risultati. - Rilevamento dei valori nullable. Un
nullnell'esempio diventaunknown; il convertitore non sa se il campo è davvero nullable (string | null) o se era semplicemente null in questo campione. Adeguare a mano in base al contratto API. - Unioni di letterali stringa. Un campo status con il valore
"active"diventastring, non"active" | "inactive" | "pending". Il convertitore non può vedere gli altri valori. - Rilevamento del tipo Date. Una stringa ISO 8601 come
"2024-04-12T10:00:00Z"rimane di tipostring.Datedi JavaScript non è un tipo JSON. - Unioni discriminate. Se un array radice contiene elementi di struttura diversa (eventi di tipi diversi, record polimorfici), il convertitore unisce tutte le chiavi in un'unica interface anziché produrre un'unione con discriminante. Per dati genuinamente eterogenei, sarà necessario scrivere l'unione a mano.
- Precisione numerica. Il
numberdi JavaScript rappresenta in modo sicuro gli interi fino a 253−1. Gli ID interi più grandi perdono precisione quando vengono analizzati daJSON.parse; se la propria API restituisce interi a 64 bit, il pattern più sicuro è inviarli come stringhe e tiparli comestring.
Quando usare questo strumento
- Avvio rapido dei tipi da una risposta API reale. Interrogare l'endpoint, incollare il JSON, ottenere un insieme iniziale di interface. Affinare a mano i campi opzionali e i letterali stringa.
- Aggiunta di tipi a un SDK di terze parti privo di tipi. Molte librerie JS più vecchie vengono distribuite senza tipi. Generarli da una risposta campione è più veloce che leggere la documentazione.
- Condivisione dei tipi tra front-end e back-end. Generare da un unico esempio canonico e copiare in entrambi i codebase (o condividere tramite un pacchetto di tipi pubblicato).
- Migrazione di un codebase JS a TypeScript. Generare tipi dai dati reali che fluiscono nell'app e annotare gradualmente le firme delle funzioni.
- Generazione di tipi per un file di configurazione. La tipizzazione rigorosa rende visibili gli errori di configurazione in fase di compilazione.
- Documentazione della struttura di un file di dati interno. La interface generata funge anche da documentazione leggibile dalla macchina.
Code-first vs Schema-first vs diretto (dove si colloca questo strumento)
Tre flussi di lavoro comuni per ottenere tipi TypeScript dai dati in runtime:
- Validatori runtime code-first: Zod, Yup, Effect Schema, Joi. Si scrive uno schema di validazione in JS che fornisce sia il parsing runtime sia un tipo TypeScript tramite inferenza. Lo schema è la fonte di verità. Ideale quando la validazione è importante quanto il tipo.
- Schema-first: si scrive un JSON Schema o una specifica OpenAPI, si generano i tipi TypeScript tramite strumenti come
quicktype,json-schema-to-typescriptoopenapi-typescript. Ideale quando un contratto API riguarda più linguaggi. - Inferenza diretta da campione (questo strumento, più la modalità plain-JSON di quicktype): incollare dati reali, ottenere tipi. Il percorso più rapido; le garanzie di validazione più deboli, perché nulla verifica i dati runtime rispetto al tipo.
La scelta giusta dipende dal fatto che la preoccupazione riguardi principalmente la verifica statica dei tipi (questo strumento è ottimo) o anche la sicurezza in runtime (in quel caso usare Zod / Effect Schema).
Errori comuni
- Trattare i tipi generati come una specifica definitiva. Sono un punto di partenza completato al 70%. Aggiungere
?per i campi opzionali,| nulldove effettivamente nullable, unioni di letterali stringa dove applicabile. - Generare da un singolo esempio quando l'API ha varianti. Un oggetto utente che a volte ha il campo
emaile a volte no verrà generato con «email obbligatoria». Eseguire su più esempi e unire i risultati, o modificare a mano. - Contrassegnare tutto automaticamente come
readonly. Utile per i flussi di dati immutabili, ma errato per gli oggetti di stato che si mutano. Usare il togglereadonlycon attenzione. - Fidarsi della precisione per ID interi grandi. Il
numberdi JavaScript arriva al massimo a 253−1. Per ID a 64 bit, trasmettere come stringhe e tipare comestring. - Confondere
interfacecontype. Strumenti diversi, compromessi diversi. L'euristica del TypeScript Handbook è «usa interface a meno che non ti serva una funzionalità che solo type offre», esattamente ciò che fa questo strumento. - Incollare JSON riservato in un convertitore lato server. Le risposte API reali contengono spesso dati dei clienti, credenziali, ID interni. La conversione esclusivamente nel browser (questo strumento) mantiene i dati sul proprio dispositivo.
Altre domande frequenti
Perché tutti i miei campi sono stati contrassegnati come obbligatori?
Perché un singolo esempio JSON non riesce a dire al convertitore quali campi sono a volte assenti nella vera API. Ogni chiave che appare nell'esempio diventa obbligatoria. Se si sa che un campo è opzionale, aggiungere un ? finale a mano: email?: string;. Per il rilevamento dell'opzionalità su più campioni, il più sofisticato CLI quicktype lo gestisce nativamente.
Perché il mio campo null è tipato come unknown?
Perché il convertitore non riesce a stabilire da un singolo null se il campo è sempre nullable (string | null) o se era semplicemente null in questo campione (string). unknown è il default conservativo; TypeScript obbligherà a restringere il tipo prima di usare il valore, il che è più sicuro di any. Modificare in string | null a mano una volta nota l'intenzione dell'API.
Devo usare interface o type?
L'euristica del TypeScript Handbook ufficiale: usare interface finché non si ha bisogno di una funzionalità fornita solo da type, principalmente tipi unione, tipi intersezione o la denominazione di un tipo primitivo. Questo convertitore segue quella regola: interface per ogni struttura oggetto, type per l'alias dell'array radice. Alcune linee guida di stile raccomandano di usare type per impostazione predefinita (Matt Pocock ha sostenuto pubblicamente questa tesi), ma il default convenzionale è interface per gli oggetti.
Il mio JSON verrà caricato da qualche parte?
No. La conversione è un IIFE JavaScript autonomo che analizza il JSON tramite JSON.parse, percorre il valore e scrive l'output TypeScript in un'area di testo. Non ci sono fetch, né chiamate di analytics che portano il contenuto JSON, né server. Questo è importante perché le risposte API reali contengono tipicamente dati dei clienti, ID interni o credenziali che non si vogliono far transitare attraverso terze parti.
E JSDoc, Zod o la validazione runtime?
Questo strumento emette solo tipi TypeScript in fase di compilazione: nessun validatore runtime (niente Zod / Yup / Effect Schema), nessun commento JSDoc. Se si ha bisogno di validazione runtime che funzioni anche come tipo statico, scrivere lo schema in Zod e usare z.infer<typeof Schema> di Zod per derivare il tipo. Se si dispone di un JSON Schema e si vogliono sia la validazione runtime sia i tipi TS, json-schema-to-typescript + AJV è l'abbinamento convenzionale.
Perché non c'è il prefisso I nei nomi delle interface?
Perché la maggior parte delle linee guida di stile TypeScript moderne lo elimina. La TypeScript Style Guide di Google ne sconsiglia esplicitamente l'uso; la comunità React ha convergito su PascalCase senza prefisso. La convenzione storica IUser proveniva dall'influenza di C# / Java sul primo TypeScript; la pratica attuale è il semplice User.