GraphQL to TypeScript: สร้าง Type จาก SDL ได้ในไม่กี่วินาที
เรียนรู้วิธีใช้ GraphQL to TypeScript converter เพื่อแปลง GraphQL SDL เป็น TypeScript interface และ enum พร้อมตัวอย่าง กฎการ map type และแนวทางใช้งานจริง
Table of Contents
การดูแลให้ GraphQL schema และ TypeScript model ตรงกันตลอดเวลาเป็นงานซ้ำที่ผิดพลาดได้ง่าย field ที่ nullable อาจถูกเขียนเป็น required, enum อาจขาดสมาชิกหนึ่งค่า หรือ ID อาจถูกกำหนดเป็น number โดยไม่ตั้งใจ ความคลาดเคลื่อนเล็ก ๆ เหล่านี้มักไม่แสดงผลทันที แต่จะกลายเป็น bug ที่ตามหายากเมื่อข้อมูลจริงไหลผ่านระบบ
GraphQL to TypeScript converter ช่วยแปลง GraphQL Schema Definition Language หรือ SDL ให้เป็น TypeScript definition ที่อ่านง่ายได้โดยตรงใน browser เพียงวาง schema แล้วกดแปลง จากนั้น copy ผลลัพธ์หรือดาวน์โหลดไฟล์ types.ts ไปใช้ได้ทันที เหมาะกับ prototype, ตัวอย่างใน documentation, test fixture และ schema ขนาดเล็กที่ยังไม่จำเป็นต้องติดตั้ง code-generation pipeline เต็มรูปแบบ
คู่มือนี้อธิบายกฎการแปลง type, ความหมายของ nullability และ list พร้อมตัวอย่างการนำผลลัพธ์ไปใช้ใน workflow จริง เพื่อให้ generated code เป็นจุดเริ่มต้นที่ปลอดภัย ไม่ใช่แค่โค้ดที่ดูถูกต้องในครั้งแรก
ทำไมควรใช้ GraphQL to TypeScript?
- ลดงานพิมพ์ซ้ำ: แปลง schema declaration เป็น TypeScript โดยไม่ต้องเขียน field, list และ enum ทุกตัวด้วยมือ
- ลด schema-model drift: ใช้ GraphQL SDL เป็น source of truth แทนการดูแล type สองชุดที่อาจเปลี่ยนไม่พร้อมกัน
- รักษา nullability: field ที่ไม่มี ! จะกลายเป็น union กับ null ทำให้ TypeScript เตือนจุดที่ต้องรองรับค่าที่ไม่มี
- Map scalar อย่างสม่ำเสมอ: scalar มาตรฐานของ GraphQL ถูกแปลงเป็น TypeScript primitive ที่เหมาะสมทุกครั้ง
- นำผลลัพธ์ไปใช้สะดวก: copy definition ได้ทันที หรือดาวน์โหลดเป็นไฟล์ .ts เพื่อวางใน project
- ทำงานแบบส่วนตัวใน browser: การแปลงเกิดขึ้นฝั่ง client จึงไม่ต้องส่ง schema ไปยัง conversion service ภายนอก
ฟีเจอร์สำคัญ
| ฟีเจอร์ | การทำงาน |
|---|---|
| SDL conversion | อ่าน block แบบ type, input, interface และ enum |
| Scalar mapping | แปลง String, ID, Int, Float และ Boolean เป็น TypeScript primitive |
| Nullability handling | เติม | null เมื่อ GraphQL field อนุญาตให้เป็น null |
| List handling | แปลง list notation ของ GraphQL เป็น TypeScript array |
| Exportable definitions | สร้าง exported interface และ enum ที่มีค่าเป็น string |
| Quick actions | copy output หรือดาวน์โหลดเป็น types.ts |
| Conversion summary | แสดงจำนวน type, input, interface และ enum ที่สร้างได้ |
- Output อ่านง่าย: object type, input object และ GraphQL interface ถูกสร้างเป็น TypeScript interface มาตรฐาน จึงเข้าใจและนำไปใช้ต่อได้ง่าย
- มี schema ตัวอย่าง: ตัวอย่างในเครื่องมือครอบคลุม object relation, enum, input, list รวมถึง field แบบ required และ nullable
- ไม่ต้องตั้งค่า project: ไม่ต้องติดตั้ง package, สร้าง config, รัน build หรือจำคำสั่ง CLI
วิธีใช้งาน
- เปิดตัวแปลง: ไปที่ เครื่องมือ GraphQL to TypeScript ด้วย browser รุ่นใหม่
- วาง SDL: ใส่ definition แบบ type, input, interface และ enum ที่ต้องการลงในช่อง GraphQL schema หรือโหลดตัวอย่างเพื่อดูรูปแบบที่รองรับ
- สร้าง TypeScript: กดแปลง เครื่องมือจะ parse declaration ที่รองรับและแสดงจำนวน definition แต่ละชนิด
- ตรวจสอบ output: เช็ก scalar, รูปแบบ list, nullability, custom scalar และ convention เฉพาะของ project ก่อนนำไปใช้
- Copy หรือ download: คัดลอก definition ลง clipboard หรือดาวน์โหลด types.ts แล้ววางใน source directory ที่เหมาะสม
ทำความเข้าใจการ Map Type จาก GraphQL ไป TypeScript
หัวใจของการแปลงไม่ใช่แค่เปลี่ยน syntax แต่คือการถ่ายทอดความหมายของ GraphQL type system ไปยัง TypeScript ให้แม่นพอที่ compiler จะช่วยป้องกันข้อผิดพลาดได้
การ map built-in scalar
ตัวแปลงใช้กฎตรงไปตรงมาสำหรับ scalar มาตรฐานห้าชนิด:
- GraphQL String กลายเป็น TypeScript string
- GraphQL ID กลายเป็น string ซึ่งสอดคล้องกับรูปแบบ identifier ที่ serialize ผ่าน API โดยทั่วไป
- GraphQL Int และ Float กลายเป็น number เพราะ JavaScript ใช้ number type เดียวสำหรับค่าตัวเลขทั่วไป
- GraphQL Boolean กลายเป็น boolean
ชื่อ object type และ custom scalar จะยังคงเป็น named reference เช่น author: User! จะใช้ type User ส่วน createdAt: DateTime! จะยังคงชื่อ DateTime ไว้ คุณต้องประกาศหรือแทน custom scalar ตามกติกาของ application เอง วิธีง่ายที่พบบ่อยคือเพิ่ม type DateTime = string แต่บาง project อาจใช้ branded string, ISO date type หรือ model เฉพาะ domain เพื่อป้องกันการส่ง string ทั่วไปผิดตำแหน่ง
การคงชื่อ custom scalar ไว้ดีกว่าการเดา เพราะชื่อเดียวกันอาจมี runtime representation ต่างกันในแต่ละระบบ ตัวอย่างเช่น Decimal อาจเป็น number, string หรือ class จาก decimal library ก็ได้ การ review หลัง generate จึงเป็นขั้นตอนที่ห้ามข้าม
Required field และ nullable field
GraphQL field เป็น nullable โดย default declaration displayName: String หมายความว่า resolver สามารถคืน string หรือ null ได้ ดังนั้น TypeScript ที่สร้างออกมาคือ displayName: string | null หากเพิ่ม non-null marker เป็น displayName: String! ผลลัพธ์จะเป็น displayName: string
รายละเอียดนี้มักหายไประหว่างการเขียน type ด้วยมือ การเก็บ nullability ไว้ทำให้ code ฝั่ง consumer ต้องจัดการข้อมูลที่อาจไม่มีอย่างชัดเจน และทำให้ schema change เห็นผลผ่าน type checker ได้เร็วขึ้น หาก backend เปลี่ยน field จาก required เป็น nullable แต่ type ฝั่ง client ยังเป็น string อย่างเดียว code อาจเรียก method บน null ใน runtime ได้
ควรแยกระหว่าง nullability กับ TypeScript property optionality ให้ชัดเจน property ที่ต้องมีแต่ value เป็น string | null หมายถึง key ควรอยู่ใน response แต่ค่าของมันอาจเป็น null ส่วน property แบบ name?: string หมายถึง key อาจไม่อยู่เลย กรณี GraphQL operation ที่เลือก field เพียงบางส่วน, partial response หรือ incremental delivery อาจต้องใช้ operation-specific type เพิ่มเติม
List, enum, input และ interface
GraphQL list เช่น tags: [String!] ถูกแปลงเป็น TypeScript array และ outer nullability จะกำหนดว่า list ทั้งก้อนเป็น null ได้หรือไม่ ส่วน enum จะสร้างเป็น string-valued enum ที่อ่านง่ายและใช้ตรวจค่าผิดได้:
export enum UserRole {
ADMIN = 'ADMIN',
EDITOR = 'EDITOR',
}
GraphQL object type, input object และ interface จะถูกสร้างเป็น TypeScript interface ทั้งหมด รูปแบบนี้เหมาะกับ server model, fixture, documentation และ shared schema reference เพราะ TypeScript ใช้ structural typing อยู่แล้ว อย่างไรก็ตามความหมายของแต่ละ declaration ใน GraphQL ยังต่างกัน input ใช้รับ argument ส่วน object type ใช้เป็นผลลัพธ์ และ GraphQL interface เป็นสัญญาที่หลาย object type implement ได้
ต้องจำด้วยว่า schema-level type บอก field ที่เป็นไปได้ทั้งหมด แต่ GraphQL operation ส่งกลับเฉพาะ field ที่ query เลือก ถ้า schema มี User สิบ field แต่ query ขอเพียง id และ name response ไม่ได้มีครบตาม interface ทั้งหมด สำหรับ production client ที่ต้องการ type ตรงกับแต่ละ query และ mutation ควรใช้ operation-aware code generator เป็น source ของ response type
เครื่องมือนี้ตั้งใจรองรับ SDL ทั่วไปแบบรวดเร็ว advanced directive, schema extension, multiline description ที่ซับซ้อน, nested list nullability หลายชั้น และ construct พิเศษควรได้รับการตรวจด้วยมือ ให้มอง generated code เป็น baseline ที่ดี ไม่ใช่ contract ที่เชื่อได้โดยไม่ review
กรณีใช้งานจริง
สร้าง API prototype อย่างรวดเร็ว
สมมติทีมกำลังออกแบบ product API ที่มี Product, Category และ CreateProductInput เมื่อแปลง draft SDL แล้ว frontend และ backend จะได้ interface สำหรับ mock service และ proof of concept ทันที ทีมสามารถปรับ schema แล้ว generate ใหม่ แทนการเสียเวลาช่วง prototype ไปกับการแก้ model ซ้ำสองที่
วิธีนี้ช่วยให้การคุยเรื่อง API ชัดขึ้นด้วย เพราะทุกคนเห็นว่า field ใด required, ค่าใด nullable และ enum รองรับสถานะใดบ้าง ก่อนที่จะลงทุนสร้าง resolver หรือหน้าจอจริง
ใช้เป็นฐานสำหรับ resolver และ service model
ฝั่ง server สามารถใช้ generated interface เป็น baseline ของ resolver return value และ service boundary ได้ ถ้า schema กำหนด Product.price เป็น non-null แต่ implementation มีทางคืน null TypeScript จะช่วยเผยความไม่ตรงกันได้ก่อน deploy นอกจากนี้ type ที่สร้างออกมายังช่วยชี้ให้เห็นว่าจุดใดควรแยก database entity ออกจาก public API model เพื่อไม่ให้ field ภายในรั่วออกไป
สร้าง fixture และตัวอย่าง
Test, Storybook story และ documentation มักต้องใช้ GraphQL object ตัวอย่าง Interface ที่ชัดเจนช่วยจับ fixture ที่ผิด เช่น ขาด id ที่ required, ใช้ enum member ที่ไม่มีอยู่จริง หรือใส่ number ให้ field ที่ต้องเป็น string การพบปัญหาระหว่าง type checking เร็วและเข้าใจง่ายกว่าการรอให้ตัวอย่างล้มตอน runtime
ทีมยังสามารถเก็บ factory function ที่คืน generated type เพื่อสร้าง test data แบบสม่ำเสมอ เมื่อ schema เพิ่ม required field compiler จะชี้ fixture ที่ต้องแก้ ทำให้ test data ไม่ล้าหลัง API โดยเงียบ ๆ
ย้าย JavaScript project ไป TypeScript
หากกำลังเพิ่ม TypeScript ให้ GraphQL project เดิม schema คือรายการ domain type ที่มีอยู่แล้ว Generate baseline file, เพิ่ม alias สำหรับ custom scalar แล้วค่อยนำ definition ไปใช้ทีละ module จะได้ type coverage ที่มีประโยชน์อย่างรวดเร็วโดยไม่บังคับให้ migration เสร็จทั้งหมดในครั้งเดียว
เริ่มจาก boundary ที่รับและส่งข้อมูล GraphQL ก่อน จากนั้นค่อยเพิ่ม type ให้ business logic ภายใน แนวทางนี้ลดจำนวน any ในจุดเสี่ยงสูงและยังรักษาขอบเขตงานให้จัดการได้
แนวทางปฏิบัติที่ดี
- Review ทุกไฟล์ที่ generate: เครื่องมือช่วยลดงานซ้ำ แต่มีเพียงทีมของคุณที่รู้ representation ที่ถูกต้องของ custom scalar และ domain value
- ให้ schema เป็นแหล่งอ้างอิงหลัก: Generate ใหม่เมื่อ SDL เปลี่ยน และหลีกเลี่ยง manual edit ถาวรที่สร้างซ้ำไม่ได้
- แยก schema type กับ operation type: ใช้ schema-wide definition สำหรับ domain reference และใช้ operation-aware tooling เมื่อ client ต้องการ shape ที่ตรงกับ query หรือ mutation จริง
- ทดสอบสมมติฐานเรื่อง nullability: ให้ความสำคัญเป็นพิเศษเมื่อเพิ่มหรือลบ ! เพราะมีผลทั้งต่อ runtime guarantee และ TypeScript type
- Format และ type-check ก่อน commit: รัน formatter และ type checker ของ project หลังนำไฟล์ที่ดาวน์โหลดเข้า codebase
- ขยับไป full code generation เมื่อจำเป็น: schema ขนาดใหญ่, fragment, directive, union, subscription และ CI automation ควรใช้ GraphQL code-generation pipeline แบบเต็ม
สร้าง TypeScript Definition ของคุณตอนนี้
หากไม่ต้องการแปล schema field ด้วยมืออีกต่อไป เปิด GraphQL to TypeScript converter วาง SDL แล้วสร้าง interface และ enum ที่ชัดเจนได้ในไม่กี่วินาที จากนั้น review ผลลัพธ์ เพิ่ม custom scalar alias ที่ project ต้องใช้ และนำไฟล์ไปเป็นฐานของ GraphQL development ที่ปลอดภัยขึ้น
เครื่องมือที่เกี่ยวข้อง:
- JSON to TypeScript Converter — สร้าง TypeScript definition จากข้อมูลตัวอย่าง JSON
- JSON to GraphQL Schema — แปลงโครงสร้าง JSON ให้เป็น GraphQL SDL
- GraphQL Formatter — จัดรูปแบบและทำความสะอาด GraphQL query หรือ schema text
ขอให้สร้าง type ได้อย่างราบรื่น!