Come funziona l'inferenza da JSON a TypeScript
L'inferenza è un singolo passaggio sull'albero JSON analizzato. Lo strumento legge ogni valore, sceglie un tipo TypeScript per esso, e poi scrive un'interfaccia per ogni oggetto trovato.
- Analizza l'esempio JSON con il parser nativo del browser e rifiuta l'input malformato con un suggerimento di riga/colonna.
- Rileva un tipo TypeScript per ogni valore —
string,number,boolean,null, array o oggetto annidato. - Assegna ad ogni oggetto annidato un nome di interfaccia derivato dalla chiave della proprietà parent (quindi
user.addressdiventa un'interfacciaAddress). - Unisce i tipi degli elementi in ogni array in modo che una lista di
{id: 1}e{id: 2, label: "x"}produca un tipo union con i campi opzionali corretti. - Applica le tue opzioni (interface vs. type, readonly, optional-nullable) e emette le dichiarazioni in ordine di dipendenza in modo che il file venga compilato senza riferimenti in avanti.
Perché generare tipi TypeScript da JSON?
- La maggior parte dei bug di forma è intercettabile al momento della compilazione se il tipo di risposta è scritto. Inferire un'interfaccia da un payload reale ne scrive la maggior parte automaticamente, e la modalità `strict` intercetta il campo che i documenti hanno dimenticato di menzionare.
- Abbinare le interfacce inferite con un validatore runtime come Zod o io-ts dà alla stessa forma due compiti: il completamento automatico dell'editor in fase di sviluppo e un 400 al margine quando la produzione invia qualcosa di inaspettato.
- Il language server di TypeScript espone solo i campi che conosce. Una volta importata l'interfaccia inferita, il completamento automatico funziona nel momento in cui digiti il punto — niente più cast `as any` sulla risposta e una ricerca grep frustrante nel repository.
- Se stai per scrivere una specifica OpenAPI, un'interfaccia inferita è una prima bozza rapida dello schema di risposta. Vorrai comunque esempi scritti a mano e vincoli, ma i nomi delle proprietà e i tipi sono già corretti.
Applicazioni comuni
L'inferenza è più utile quando esiste un payload reale ma non uno schema.
- Tipizzazione dei payload webhook di terze parti da Stripe, GitHub o Twilio prima di scrivere un handler.
- Bootstrap dei tipi per un'API REST interna in modo che il team front-end possa iniziare a codificare contro di essa lo stesso giorno in cui il back-end viene completato.
- Generazione di un punto di partenza per uno schema Zod, io-ts o Valibot da una risposta API osservata.
Come appare l'output?
Dato un documento JSON di esempio e un nome radice, il generatore produce un albero di interfacce, una per ogni oggetto annidato. Per l'input qui sotto con nome radice User:
Incolla {"id":1,"name":"Alice","tags":["a","b"],"address":{"city":"Paris"}} con nome radice User e il generatore produce:
export interface User {
id: number;
name: string;
tags: string[];
address: Address;
}
export interface Address {
city: string;
}
Nota che address è stato promosso alla sua propria interfaccia con nome — questo è l'output ordinato per dipendenza. Lo stesso JSON con lo stile di dichiarazione type invece emetterebbe export type User = {...}; con l'interruttore readonly attivo, ogni proprietà ottiene il modificatore readonly.
Opzioni del generatore
Stile di dichiarazione
Scegli interface (l'idioma TypeScript standard per le forme degli oggetti) o type (utile se avrai bisogno di tipi mappati, tipi condizionali o intersezioni in seguito). Entrambi producono un comportamento runtime identico; la scelta è una preferenza di stile del codice.
Campi nullable opzionali
Quando un valore campionato è null, il tipo del campo diventa T | null. Attivare questa opzione aggiunge anche un modificatore ? in modo che il campo sia opzionale lato TypeScript — utile quando l'API a volte omette completamente la chiave invece di restituire null.
Modificatore readonly
Aggiunge readonly a ogni dichiarazione di proprietà in modo che l'interfaccia emessa corrisponda a un modello di dati immutabile. Utile per le slice dello stato Redux, le risposte API congelate o ovunque si voglia che il compilatore segnali le mutazioni accidentali.
Supporta oggetti annidati e array?
Sì. Ogni oggetto annidato diventa un'interfaccia con nome derivata dalla chiave della proprietà parent, e gli array inferiscono il tipo degli elementi dal loro contenuto. Gli array di oggetti ottengono un'interfaccia per forma dell'oggetto, con tipi union dove le forme non concordano.
Come vengono inferiti i campi opzionali?
Attiva l'interruttore "Marca i campi nullable come opzionali" e qualsiasi campo il cui valore campionato è null ottiene un modificatore ? sulla chiave più | null nel tipo. Senza l'interruttore, il campo rimane obbligatorio e il tipo è solo T | null.
Supporta i discriminated union?
I tipi union di base emergono quando un array contiene elementi con forme miste o quando un campo porta sia un valore sia null. L'inferenza completa dei discriminated union (scegliendo type o kind come tag e dividendo le varianti) richiede più campioni — è pianificato ma non nell'attuale versione.
Posso inferire tipi da più esempi JSON?
Non ancora — l'inferitore attuale legge un campione alla volta. Se hai due payload che dovrebbero condividere un'interfaccia (ad esempio, un endpoint di lista e un endpoint di singolo elemento), il modo pratico è unirli in un unico array, generare da quello e poi rinominare i tipi union risultanti. L'inferenza da più campioni è nella roadmap perché è l'unico modo per individuare i campi presenti in una risposta e assenti in un'altra.
Incolla un payload, dai un nome alla radice, copia le interfacce. L'intera pipeline viene eseguita nel tuo browser, quindi un'API non ancora rilasciata o un corpo webhook firmato rimangono sulla tua macchina.