Skip to content
jsonforge.app
Kembali ke blog
Panduan7 menit baca

Membangkitkan Tipe TypeScript dari JSON: Panduan Praktis

Menulis interface TypeScript secara manual untuk respons API 40 field itu melelahkan dan rawan salah. Salah ketik pada nama field merusak type safety tanpa compile error. Membuat interface langsung dari sampel JSON nyata lebih cepat dan lebih akurat, selama Anda paham di mana inferensi harus menebak.

Cara kerja inferensi JSON-ke-TypeScript

Generator menelusuri pohon nilai JSON dan memetakan setiap tipe JavaScript ke padanan TypeScript-nya: string tetap string, number tetap number, boolean tetap boolean, null menjadi null (atau digabungkan ke union), array menjadi T[] dengan T diinferensi dari elemennya, dan object menjadi interface bersarang.

Sampel JSON dan interface hasil inferensinya.
json
{
  "id": 42,
  "email": "ada@example.com",
  "isActive": true,
  "roles": ["admin", "editor"],
  "profile": {
    "displayName": "Ada",
    "avatarUrl": null
  }
}
Keluaran TypeScript hasil inferensi.
typescript
interface Root {
  id: number;
  email: string;
  isActive: boolean;
  roles: string[];
  profile: {
    displayName: string;
    avatarUrl: string | null;
  };
}

Di mana inferensi harus menebak

Field opsional vs. selalu hadir: satu sampel JSON tak bisa memberi tahu generator apakah avatarUrl kadang hilang sepenuhnya (yang seharusnya avatarUrl?: string | null) atau selalu hadir tetapi kadang null. Beri generator beberapa sampel representatif, atau tandai field sebagai opsional secara manual setelah pembangkitan jika Anda tahu API menghilangkannya dalam kondisi tertentu.

Angka yang berupa ID vs. kuantitas: JSON punya satu tipe number, dan TypeScript tak bisa membedakan ID integer dari harga floating-point tanpa konteks tambahan. Sebagian generator menawarkan branded types atau literal union untuk ini; kebanyakan menghasilkan number dan menyerahkan perbedaannya pada Anda.

Array kosong: array tanpa elemen ("tags": []) tidak memberi generator petunjuk tipe elemennya, jadi generator memakai unknown[] atau any[]. Arahkan generator ke sampel yang array-nya terisi, atau anotasikan manual setelahnya.

Literal union string: generator menginferensi field status yang berisi salah satu dari "pending" | "active" | "closed" sebagai string polos kecuali ia melihat semua nilai yang mungkin dalam sampel. Bahkan saat itu, kebanyakan generator memilih tipe string yang lebih luas kecuali Anda mengaktifkan inferensi literal-union.

Tanggal: JSON tak punya tipe tanggal, jadi timestamp datang sebagai string (ISO 8601) atau angka (Unix epoch). Generator mengetikkan field tanggal sebagai string atau number, bukan Date, dan Anda tetap mem-parse-nya sendiri setelah fetching.

Ide yang sama dalam bahasa lain

Logika inferensinya (telusuri pohon, petakan tipe, beri nama object bersarang) sama untuk bahasa target apa pun; hanya sintaks keluarannya yang berubah. Struct Go mendapat pemetaan field yang sama dengan struct tag untuk nama key JSON; dataclass Python mendapat type hint dan pembungkus Optional[...] bila perlu; kelas Java atau C# mendapat field bertipe dan getter/setter atau records. Jika tim Anda bekerja lintas bahasa terhadap API yang sama, buat tipe untuk setiap bahasa dari sampel JSON yang sama agar semuanya tetap konsisten.

Bentuk yang sama sebagai struct Go.
go
type Root struct {
	ID       int     `json:"id"`
	Email    string  `json:"email"`
	IsActive bool    `json:"isActive"`
	Roles    []string `json:"roles"`
	Profile  struct {
		DisplayName string  `json:"displayName"`
		AvatarURL   *string `json:"avatarUrl"`
	} `json:"profile"`
}

Sebelum memercayai tipe yang dibangkitkan

Anggap tipe hasil generator sebagai titik awal, lalu selesaikan kontraknya sendiri. Sebelum meng-commit, cocokkan field opsional dengan dokumentasi API (satu sampel tidak cukup), ganti field string longgar yang berisi enum dengan literal union, pastikan field array kosong mendapat tipe elemen nyata dari sampel yang lebih baik, dan generate ulang setiap kali API upstream menambah atau mengganti nama field, jangan menambal interface secara manual.

FAQ

Bisakah generator JSON-ke-TypeScript menangani field yang kadang string dan kadang number?
Bisa, jika ia melihat kedua varian di antara sampel yang Anda berikan; ia seharusnya menginferensi string | number. Dengan satu sampel, ia hanya bisa mengetikkan apa yang dilihatnya. Karena itu, buat tipe dari beberapa payload representatif, bukan satu contoh happy-path.
Haruskah interface hasil pembangkitan memakai `interface` atau `type`?
Untuk kasus ini keduanya nyaris sama. `interface` lebih umum untuk bentuk object dan mendukung declaration merging; `type` lebih fleksibel untuk union dan intersection. Keduanya cocok untuk bentuk respons API, jadi ikuti konvensi kode basis Anda.
Bagaimana menjaga tipe hasil pembangkitan tetap sinkron seiring API berevolusi?
Perlakukan pembangkitan sebagai langkah yang dapat diulang, bukan copy-paste sekali jadi: simpan sampel respons nyata di repositori (atau ambil dari endpoint staging) dan bangkitkan ulang interface setiap kali sampelnya berubah, alih-alih mengedit manual berkas hasilnya. Sebagian tim mengaitkannya ke CI untuk menangkap drift secara otomatis.
Apakah ini bekerja untuk JSON yang bersarang dalam atau rekursif, seperti struktur pohon?
Nesting yang dalam menghasilkan interface bersarang tanpa masalah. Struktur rekursif (komentar yang berisi balasan dengan bentuk yang sama) membutuhkan tipe self-referential, dan kebanyakan generator tidak akan menginferensinya dari satu sampel. Tulis interface rekursifnya sekali secara manual lalu pakai ulang.

Coba alat ini

Artikel terkait