§

Esempio JSON

Preparazione dell'inferitore di tipi…
§

Interfacce TypeScript

TypeScript

I team TypeScript italiani si scontrano con questo problema presto. I grandi SDK distribuiscono client tipizzati (Stripe, Twilio, AWS), ma i servizi interni e i payload webhook di terze parti raramente lo fanno, quindi il flusso di lavoro tipico è: catturare una risposta reale nel pannello di rete, incollarla qui, dare un nome alla radice in base all'endpoint e copiare l'output nella directory dei tipi del progetto. Da lì, la modalità strict intercetta le discrepanze che la documentazione aveva dimenticato di menzionare. L'inferitore viene eseguito interamente nel tuo browser, quindi i payload delle API di staging, i corpi webhook firmati e gli endpoint non ancora rilasciati non raggiungono mai un servizio ospitato.

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.

  1. Analizza l'esempio JSON con il parser nativo del browser e rifiuta l'input malformato con un suggerimento di riga/colonna.
  2. Rileva un tipo TypeScript per ogni valore — string, number, boolean, null, array o oggetto annidato.
  3. Assegna ad ogni oggetto annidato un nome di interfaccia derivato dalla chiave della proprietà parent (quindi user.address diventa un'interfaccia Address).
  4. 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.
  5. 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.