วิธีการทำงานของการ infer JSON เป็น TypeScript
การ infer คือการ pass เดียวบน parsed JSON tree เครื่องมืออ่านแต่ละค่า เลือก TypeScript type สำหรับมัน จากนั้นเขียน interface หนึ่งรายการต่อ object ที่พบ
- Parse JSON sample ด้วย native parser ของเบราว์เซอร์และปฏิเสธ input ที่ผิดรูปแบบพร้อม hint ของบรรทัด/column
- Sniff TypeScript type สำหรับแต่ละค่า —
string,number,boolean,null, array หรือ nested object - ตั้งชื่อ interface สำหรับทุก nested object ที่ derive จาก parent property key (ดังนั้น
user.addressกลายเป็นAddressinterface) - Merge item type ทั่วทั้ง array เพื่อให้ list ของ
{id: 1}และ{id: 2, label: "x"}สร้าง union ที่มี optional field ที่ถูกต้อง - ใช้ option ของคุณ (interface vs. type, readonly, optional-nullable) และ emit declaration ตาม dependency order เพื่อให้ไฟล์ compile ได้โดยไม่มี forward reference
ทำไมต้อง generate TypeScript type จาก JSON?
- Shape bug ส่วนใหญ่ตรวจพบได้ที่ compile time ถ้า response type ถูกเขียนลง การ infer interface จาก real payload เขียนส่วนใหญ่ให้คุณ และ `strict` mode จะจับ field ที่เอกสารลืมพูดถึง
- การจับคู่ inferred interface กับ runtime validator อย่าง Zod หรือ io-ts ให้ shape เดียวทำงานสองอย่าง: editor autocomplete ระหว่าง development และ 400 ที่ edge เมื่อ production ส่งสิ่งที่ไม่คาดคิด
- Language server ของ TypeScript แสดงเฉพาะ field ที่รู้จัก เมื่อ import inferred interface autocomplete ทำงานทันทีที่คุณพิมพ์จุด — ไม่ต้องมี `as any` cast บน response และ grep ที่หงุดหงิดทั่ว repo อีกต่อไป
- ถ้าคุณกำลังจะเขียน OpenAPI spec, inferred interface คือร่างแรกที่รวดเร็วของ response schema คุณยังต้องการ example และ constraint ที่เขียนด้วยมือ แต่ชื่อ property และ type ถูกต้องแล้ว
การใช้งานทั่วไป
การ infer มีประโยชน์มากที่สุดเมื่อ real payload มีอยู่แต่ schema ไม่มี
- Typing third-party webhook payload จาก Stripe, GitHub หรือ Twilio ก่อนเขียน handler
- Bootstrap type สำหรับ internal REST API เพื่อให้ frontend team เริ่ม code ต่อได้ในวันเดียวกับที่ backend เสร็จ
- สร้าง starting point สำหรับ Zod, io-ts หรือ Valibot schema จาก API response ที่สังเกตได้
ผลลัพธ์มีลักษณะอย่างไร?
จาก JSON sample และชื่อ root ที่กำหนด generator สร้าง interface tree หนึ่งรายการต่อ nested object สำหรับ input ด้านล่างที่มีชื่อ root User:
วาง {"id":1,"name":"Alice","tags":["a","b"],"address":{"city":"Paris"}} ที่มีชื่อ root User แล้ว generator สร้าง:
export interface User {
id: number;
name: string;
tags: string[];
address: Address;
}
export interface Address {
city: string;
}
สังเกตว่า address ถูก promote เป็น named interface ของตัวเอง — นั่นคือ dependency-ordered output JSON เดียวกันที่ใช้รูปแบบการประกาศ type แทนจะ emit export type User = {...} เมื่อเปิด toggle readonly ทุก property จะได้ readonly modifier
ตัวเลือก generator
รูปแบบการประกาศ
เลือก interface (idiom TypeScript มาตรฐานสำหรับ object shape) หรือ type (มีประโยชน์ถ้าต้องการ mapped type, conditional type หรือ intersection ในภายหลัง) ทั้งสองมีพฤติกรรม runtime เหมือนกัน ทางเลือกคือความชอบในรูปแบบการเขียนโค้ด
Optional nullable field
เมื่อค่าที่ sample เป็น null type ของ field จะกลายเป็น T | null การเปิด option นี้จะเพิ่ม ? modifier ด้วย เพื่อให้ field เป็น optional ในฝั่ง TypeScript — มีประโยชน์เมื่อ API บางครั้ง omit key ทั้งหมดแทนที่จะคืน null
Readonly modifier
เพิ่ม readonly นำหน้าทุก property declaration เพื่อให้ emitted interface ตรงกับ immutable data model มีประโยชน์สำหรับ Redux state slice, frozen API response หรือทุกที่ที่ต้องการให้ compiler ตั้งค่าสถานะการ mutate โดยไม่ตั้งใจ
รองรับ nested object และ array หรือไม่?
ใช่ ทุก nested object กลายเป็น named interface ที่ derive จาก parent property key และ array อนุมาน item type จากเนื้อหา Array ของ object ได้ interface หนึ่งรายการต่อ object shape พร้อม union type ที่ shape ไม่ตรงกัน
Optional field อนุมานอย่างไร?
เปิด toggle "ทำเครื่องหมาย field ที่เป็น null ว่า optional" แล้ว field ใดก็ตามที่ค่าที่ sample เป็น null จะได้ ? modifier บน key พร้อม | null ใน type โดยไม่มี toggle field ยังคงเป็น required และ type เป็นแค่ T | null
รองรับ discriminated union หรือไม่?
Union type พื้นฐานออกมาเมื่อ array มี item ที่ shape ต่างกันหรือเมื่อ field มีทั้งค่าและ null การ infer discriminated-union เต็มรูปแบบ (เลือก type หรือ kind เป็น tag และแยก variant) ต้องการ sample หลายรายการ — อยู่ใน plan แต่ยังไม่ใน build ปัจจุบัน
สามารถ infer type จาก JSON sample หลายรายการได้หรือไม่?
ยังไม่ได้ — inferrer ปัจจุบันอ่าน sample ทีละรายการ ถ้ามี payload สองรายการที่ควร share interface (เช่น list endpoint และ single-item endpoint) วิธีแก้ปัญหาในทางปฏิบัติคือ merge เป็น array เดียว generate จากนั้น แล้วตั้งชื่อ union type ที่ได้ใหม่ การ infer จาก multi-sample อยู่ใน roadmap เพราะเป็นวิธีเดียวที่จะพบ field ที่มีใน response หนึ่งแต่ไม่มีในอีก response
วาง payload ตั้งชื่อ root คัดลอก interface pipeline ทั้งหมดรันในเบราว์เซอร์ ดังนั้น API ที่ยังไม่ release หรือ webhook body ที่มีลายเซ็นจะอยู่บนเครื่องของคุณ