JSON Toolkit

สร้าง TypeScript type จาก Schema

สรุปสำคัญ: json-schema-to-typescript และ quicktype สร้าง .d.ts ได้ในคำสั่งเดียว แต่มันเป็นเพียงร่าง: optionality, union, additionalProperties และวันที่ยังต้องมีคนตรวจ

ระดับกลางอ่านประมาณ 4 นาทีเผยแพร่ 2026-10-30อัปเดต 2026-10-30
การสร้าง TypeScript type จาก JSON Schema

สรุปสั้น ๆ: สร้างด้วย json-schema-to-typescript หรือ quicktype แล้วแก้ด้วยมือเรื่อง optionality, union, additionalProperties และวันที่; ให้ Schema เป็นต้นทางและ type เป็นผลลัพธ์ โดยบังคับด้วยขั้นตอน types:check ใน CI

คำสั่งเดียวได้ไฟล์ แต่ไม่ได้ type ที่ถูกต้อง

คำสั่งบรรทัดเดียว

npx json-schema-to-typescript schema.json > src/types/order.d.ts

มันจัดการ $ref, allOf, oneOf, anyOf และแปลง description เป็น JSDoc สำหรับการสร้างเป็นชุดพร้อม banner และ style ที่เลือกได้ ให้เรียก Node API ของมันจาก build-types.mjs เล็ก ๆ

quicktype คือทางเลือก และยังอนุมาน schema จาก JSON ตัวอย่างได้ด้วย:

npx quicktype -s schema schema.json -o order.ts --lang typescript

สี่จุดที่ต้องแก้ทีหลัง

Optionality อะไรที่ไม่อยู่ใน required จะกลายเป็น ? แต่ "มีเสมอ อาจเป็น null" กับ "อาจไม่มี" เป็นสัญญาที่ต่างกัน:

interface Order {
  remark?: string | null;   // อาจไม่มีก็ได้
  status: string;
}

ถ้า backend ส่ง remark: null เสมอ ให้ตัด ? ออกและเลิกให้ผู้ใช้ทุกคนต้องป้องกัน undefined

Union ที่ไม่มี discriminant oneOf มักกลายเป็น A | B ซึ่ง TypeScript narrow ไม่ได้หากไม่มีฟิลด์ literal ให้เพิ่มพร็อพเพอร์ตี้ type ที่ค่าคงที่ในแต่ละสาขาของ Schema

additionalProperties เมื่อละไว้หรือเป็น true บางครั้งให้ [k: string]: unknown บางครั้งให้ any แบบแรกปลอดภัย แบบหลังปิดการตรวจชนิดของ object ทั้งก้อนอย่างเงียบ ๆ

รูปแบบวันที่ format: "date-time" คือสตริงบน wire การแมปเป็น Date หมายความว่าต้อง deserialize ด้วย มิฉะนั้นค่าตอนรันไทม์ยังเป็นสตริงขณะที่ type โกหก

ให้ทิศทางคงที่

Schema คือต้นทาง type คือผลลัพธ์ การสร้าง Schema จาก type ที่เขียนด้วยมือยอมรับได้เฉพาะเมื่อการสร้างใหม่เป็นภาคบังคับและถูกบังคับใน CI — มิฉะนั้นทั้งสองฝั่งจะคลาดกันและไม่มีใครรู้ว่าฝั่งไหนเป็นหลัก

ใส่ไว้ใน pipeline

"types:gen": "json2ts -i schemas/ -o src/types/generated",
"types:check": "pnpm types:gen && git diff --exit-code src/types/generated"

types:check คือส่วนที่สำคัญ: แก้ Schema โดยไม่สร้างใหม่แล้ว CI ล้มเหลว

คำถามที่พบบ่อย

ทำไมไฟล์ที่สร้างขึ้นมี any?

มักมาจาก additionalProperties ที่เป็น true หรือถูกละไว้ ซึ่ง generator บางตัวแมปเป็น [k: string]: any ให้แทนด้วย unknown หรือฟิลด์ที่ระบุชัด เพราะ any ปิดการตรวจชนิดของ object ทั้งก้อน

ควรแก้ฟิลด์ optional หลังสร้างอย่างไร?

อะไรที่ไม่อยู่ใน required จะกลายเป็น ? แต่ "มีเสมอ อาจเป็น null" ต่างจาก "อาจไม่มี" ถ้า backend ส่งฟิลด์นี้เสมอ ให้ตัด ? ออก

CI ควรล้มเหลวเมื่อ Schema กับ type คลาดกันไหม?

ควร สคริปต์ types:check ที่สร้างใหม่แล้วรัน git diff --exit-code จะทำให้ build ล้มเหลวทันทีที่ Schema เปลี่ยนโดยไม่สร้างใหม่

อ่านเพิ่มเติม