เมื่อก่อนผมชอบพูดแบบตั้งใจให้แรงว่า TypeScript คือภาษาที่ดีที่สุดสำหรับ Codex ตอนนี้ผมจะพูดให้แม่นยำกว่าเดิม: สำหรับงาน frontend และ full-stack ระดับ production ที่ผมทำจริง TypeScript คือ environment ที่ทำให้ควบคุม ตรวจสอบ และใช้งาน Codex อย่างมีเหตุผลได้ง่ายที่สุด
คำสำคัญไม่ใช่ “TypeScript” แต่คือ การควบคุม AI coding agent เก่งมากในการสร้างโค้ดที่ดูสมเหตุสมผล แต่ production engineering ต้องการมากกว่านั้น: โค้ดต้องเคารพ contract เดิม รักษา behavior ผ่าน refactor และ fail ให้เร็วเมื่อ assumption ผิด TypeScript ทำให้ constraint เหล่านี้จำนวนมากกลายเป็นข้อมูลที่เครื่องอ่านและตรวจสอบได้มากกว่า JavaScript แบบธรรมดา
Codex ต้องการอะไรจาก codebase จริง ๆ
Prompt ที่ดีมีประโยชน์ แต่เป็นเพียงส่วนหนึ่งของ context ตัว codebase เองอาจช่วยอธิบาย task หรือบังคับให้ model เดา ในทางปฏิบัติ environment ที่แข็งแรงคือที่ที่ assumption สำคัญมองเห็นได้และตรวจสอบอัตโนมัติ
- Function signature กำหนด input และ output ที่ถูกต้อง
- Interface และ type ทำให้ shape ของ domain object ชัดเจน
- Union และ enum จำกัด state ที่เป็นไปได้
- Compiler เปลี่ยน assumption ที่ผิดจำนวนมากเป็น error ที่ชัดเจนทันทีหลัง edit
AI agent ไม่จำเป็นต้องเข้าใจทั้ง application อย่างสมบูรณ์ ถ้า codebase สามารถตอบกลับทันทีเมื่อ contract ถูกทำลาย Feedback loop ยิ่งสั้น พื้นที่สำหรับการเดาอย่างมั่นใจก็ยิ่งน้อย
Type คือ context ที่ตรวจสอบได้ ไม่ใช่แค่ documentation
TypeScript ที่ดีอธิบาย design intent ให้คนอ่าน ใน workflow อัตโนมัติมันมีค่ามากขึ้นเพราะ documentation นั้นตรวจสอบด้วยเครื่องได้ เช่น:
type PaymentResult =
| { ok: true; receiptId: string }
| { ok: false; code: "declined" | "timeout" };
function getReceiptId(result: PaymentResult) {
if (result.ok) return result.receiptId;
return result.receiptId;
// TypeScript: Property 'receiptId' does not exist
// on the failure branch.
}ใน JavaScript ความผิดพลาดแบบเดียวกันอาจดูปกติจนกว่า branch นั้นจะถูก execute ตอน runtime แต่ TypeScript สามารถ reject assumption ก่อน merge สำหรับ Codex, compiler error จึงไม่ใช่แค่เส้นแดงใน editor แต่เป็น signal ที่ค่อนข้างแม่นว่ามันเข้าใจอะไรผิด
เพราะเหตุนี้ผมจึงชอบ domain type ที่ชัดเจนมากกว่าโครงสร้างกว้าง ๆ อย่าง Record<string, any> ยิ่ง type อธิบาย reality ได้ดี codebase ก็ยิ่งเป็น context ที่ดีสำหรับทั้ง developer และ AI
Compiler เปลี่ยนความผิดพลาดให้เป็น feedback loop
ผมไม่เชื่อ workflow แบบ “ให้ Codex เขียนโค้ดแล้วรับคำตอบแรกเลย” กระบวนการที่ไว้ใจได้ต้อง iterative:
task → inspect → edit → typecheck → lint → test → review diffลำดับนี้ดูน่าเบื่อ และนั่นคือเหตุผลที่มันแข็งแรง หลัง change ที่มีความหมาย environment จะตอบกลับ Type error จับ contract ที่พัง, lint จับปัญหาอีกประเภท, test ตรวจ behavior ที่ type บอกไม่ได้ และ final diff ยังต้อง human review
Prompt ที่ฉลาดอาจทำให้ครั้งแรกดีขึ้น แต่ verification loop ที่แข็งแรงทำให้ ทุกครั้งดีขึ้น สำหรับ production อย่างหลังสำคัญกว่ามาก
Refactor ใหญ่คือจุดที่ TypeScript มีค่ามากที่สุด
Small edit แบบแยกส่วนง่ายสำหรับ coding assistant แทบทุกตัว สิ่งที่ยากคือ change ที่กระจายไปหลายสิบไฟล์ เช่น rename domain field, เปลี่ยน API response, ทำ component props ให้เข้มขึ้น, แยก union หรือแทน abstraction เก่า
ใน TypeScript, breaking change จะสร้างแผนที่ของ assumption ที่ได้รับผล Compiler แสดงว่าที่ไหนยังใช้ contract เก่าอยู่ Codex สามารถไล่แก้และตรวจสอบใหม่ทุก pass ได้ สิ่งนี้ไม่ได้ทำให้ refactor ถูกต้องอัตโนมัติ แต่ทำให้ blast radius มองเห็นได้
สิ่งที่ TypeScript ช่วยไม่ได้
TypeScript เป็น guardrail ไม่ใช่ proof ว่าโปรแกรมถูกต้อง
- Business logic ผิด: โค้ดที่ typed ดีมากก็ยังคำนวณผิดได้
- Runtime data: API, database, form หรือ third-party service อาจส่งข้อมูลไม่ตรงกับ compile-time assumption
- Product context ไม่พอ: compiler ไม่รู้ว่า flow มีไว้ทำไม หรือ edge case ไหนสำคัญกับ user
- Security และ architecture: type ที่ valid ไม่ได้การันตี authorization, caching, database boundary หรือ infrastructure ที่ถูกต้อง
ดังนั้น runtime validation, tests, logging, observability และ review ยังจำเป็น Typecheck ผ่านไม่ได้แปลว่า feature ถูกต้อง
Workflow ที่ผมใช้กับ AI-assisted change
- กำหนด goal ให้แคบ อะไรต้องเปลี่ยน อะไรห้ามเปลี่ยน และ acceptance criteria คืออะไร
- ให้ Codex inspect ก่อน edit Existing type, call site, test และ module ใกล้เคียงมักมีประโยชน์กว่า prompt ยาว ๆ
- เลือก change ที่เล็กที่สุดแต่ครบ Focused diff ตรวจสอบง่ายกว่า rewrite ที่ไม่เกี่ยวข้อง
- รัน typecheck และ lint ทันที Structural error ควรโผล่ตอน change ยังเล็ก
- รัน test ที่เกี่ยวข้องและเพิ่ม test เมื่อ behavior เปลี่ยน Type ตรวจ contract; test ตรวจ behavior
- Review final diff เอง Naming, architecture, duplication, edge case และ implementation แก้ปัญหาต้นฉบับจริงหรือไม่
เมื่อไร JavaScript ก็เพียงพอ
นี่ไม่ใช่การบอกว่า JavaScript แย่ สำหรับ script เล็ก, prototype ชั่วคราว, automation ง่าย ๆ หรือ code ที่มี shared state น้อย TypeScript อาจไม่ได้เพิ่ม value มาก Project JavaScript ที่มี tests แข็งแรงและ convention ชัดก็เป็น environment ที่ดีสำหรับ AI ได้
ข้อสรุปของผมแคบกว่านั้น: codebase ยิ่งใหญ่ อายุยาว และมีหลายคนแก้ constraint ที่เครื่องตรวจได้ก็ยิ่งมีค่า และช่วงเดียวกันนั้น error จาก AI ก็มีต้นทุนสูงขึ้น
เหตุผลจริงที่ผมชอบ TypeScript กับ Codex
TypeScript ไม่ได้ทำให้ Codex ฉลาดขึ้น มันทำให้ environment ยอมรับ assumption ที่แย่ได้น้อยลง
ใน production ผมไม่ได้ต้องการแค่ agent ที่สร้างสรรค์ แต่ต้องการ agent ที่ทำงานใน system ซึ่งบอกตลอดว่าเมื่อไรผิด Type, compiler error, lint, test และ human review รวมกันสร้าง system นี้
ดังนั้นที่ผมบอกว่า TypeScript ทำงานกับ Codex ได้ดีมาก ไม่ใช่เรื่อง language fandom แต่คือ feedback ที่เร็วและตรวจสอบด้วยเครื่องได้: ambiguity น้อยลง, blast radius เล็กลง, refactor ปลอดภัยขึ้น และ engineering speed ที่เชื่อถือได้มากขึ้นเมื่อ verification ถูกทำจริงจัง