กลับไปหน้าบทความ
#ts-pattern#TypeScript#pattern matching#union type#frontend

ts-pattern: ทำให้โค้ด TypeScript อ่านง่ายและเช็กเงื่อนไขได้ครบขึ้น

ts-pattern คือไลบรารีที่นำแนวคิด pattern matching มาใช้ใน TypeScript เพื่อทำให้โค้ดที่มีเงื่อนไขหลายแบบอ่านง่ายขึ้น กระชับขึ้น และช่วยเช็กได้ว่ารองรับทุกกรณีสำคัญแล้วหรือยัง

27 มิถุนายน 2569อ่านประมาณ 2 นาที

แชร์บทความ

ts-pattern: ทำให้โค้ด TypeScript อ่านง่ายและเช็กเงื่อนไขได้ครบขึ้น

ts-pattern: ทำให้โค้ด TypeScript อ่านง่ายและเช็กเงื่อนไขได้ครบขึ้น

เคยไหม เขียน TypeScript แล้วต้องเจอกับ if/else หรือ switch ที่ซ้อนหลายชั้นจนกลับมาอ่านเองแล้วยังงงว่าโค้ดกำลังตัดสินใจอะไรอยู่บ้าง ปัญหานี้เกิดขึ้นบ่อยมาก โดยเฉพาะในงานที่มีหลายสถานะ หลายรูปแบบข้อมูล และ business logic ที่ค่อย ๆ ซับซ้อนขึ้นตามการเติบโตของโปรเจกต์

หนึ่งในเครื่องมือเล็ก ๆ ที่ช่วยให้โค้ดลักษณะนี้ชัดขึ้นมากคือ ts-pattern ไลบรารีที่พาแนวคิด pattern matching มาอยู่ในโลกของ TypeScript ทำให้การจัดการเงื่อนไขหลายรูปแบบเป็นระเบียบ อ่านง่าย และลดโอกาสพลาดบาง case ได้อย่างมีนัยสำคัญ

ts-pattern คืออะไร

ts-pattern เป็นไลบรารีสำหรับเขียน logic แบบจับคู่รูปแบบของข้อมูล หรือที่เรียกว่า pattern matching แทนที่จะค่อย ๆ เช็กเงื่อนไขทีละขั้นเหมือน if/else หรือ switch เราสามารถประกาศได้เลยว่า ถ้าข้อมูลมีหน้าตาแบบนี้ ให้ทำอะไร

แนวคิดหลักของมันคือ:

  • match ข้อมูลที่รับเข้ามา
  • ระบุ pattern ที่ต้องการจับในแต่ละกรณี
  • ปิดท้ายด้วย .exhaustive() เพื่อบังคับให้เช็กว่าครบทุกกรณีแล้ว

จุดเด่นสำคัญคือมันทำงานร่วมกับ TypeScript ได้ดีมาก โดยเฉพาะกับ union type, type narrowing และ exhaustive checking

ทำไมโค้ดแบบเดิมถึงเริ่มอ่านยาก

ตัวอย่างที่พบได้บ่อยในหลายโปรเจกต์คือการจัดการสถานะของการโหลดข้อมูล เช่น

  • loading
  • success
  • error
  • empty

ในโค้ดแบบทั่วไป หลายคนมักเริ่มจาก switch(status) แล้วภายในบาง case ยังมีการแตกเงื่อนไขต่ออีกที เมื่อเวลาผ่านไป โค้ดจะยาวขึ้น มีทางเลือกมากขึ้น และความเสี่ยงที่จะลืมรองรับบางกรณีก็เพิ่มขึ้นตาม

ปัญหาที่ตามมาคือ:

  • อ่าน flow การตัดสินใจยาก
  • refactor แล้วไม่มั่นใจว่าครบทุกกรณี
  • เมื่อทีมเพิ่ม state ใหม่ อาจเกิด bug ตอน runtime โดยไม่รู้ตัว

จุดแข็งของ ts-pattern ที่หลายคนชอบ

เหตุผลที่ ts-pattern ได้รับความนิยมคือมันไม่ได้ช่วยแค่ให้โค้ด “สวย” ขึ้น แต่ช่วยให้โค้ด “ปลอดภัย” ขึ้นด้วย

ข้อดีที่เห็นชัดมีดังนี้:

  • โค้ดกระชับและอ่านง่ายขึ้น
  • ลดการตกหล่นของเงื่อนไข
  • refactor ได้มั่นใจขึ้น
  • ใช้กับ TypeScript union type ได้ดีมาก
  • ทำให้ intent ของโค้ดชัดเจนตั้งแต่แรก

โดยเฉพาะ .exhaustive() ถือเป็นคุณสมบัติที่มีประโยชน์มาก เพราะเมื่อมีการเพิ่ม state ใหม่ใน type ระบบจะเริ่มเตือนทันทีหากยังมีจุดที่ match ไม่ครบ แทนที่จะปล่อยให้ bug ไปเกิดตอนใช้งานจริง

จับคู่ตาม shape ของข้อมูลได้ตรงกว่าเดิม

สิ่งที่น่าสนใจคือ ts-pattern ไม่ได้จำกัดอยู่แค่การเช็กค่าธรรมดา แต่สามารถจับคู่ได้ตามโครงสร้างข้อมูล เช่น object, array, nested structure และเงื่อนไขที่ซับซ้อนกว่าเดิม

ตัวอย่างรูปแบบข้อมูลที่พบได้บ่อย:

{ status: 'success', data: [...] }
{ status: 'error', error: 'timeout' }
{ status: 'loading' }

แทนที่จะเขียนโค้ดไล่เช็กทีละ field เราสามารถอธิบายได้ตรง ๆ ว่า หากข้อมูลมีโครงสร้างแบบใด ให้ไปทำงานเส้นทางนั้นเลย

ภาพจำง่าย ๆ คือ:

  • if/else เหมือนเดินเลือกทางทีละแยก
  • pattern matching เหมือนมองแผนผังทั้งหมดก่อน แล้วระบุเส้นทางตามรูปแบบของข้อมูลทันที

แนวคิดนี้ทำให้โค้ดคล้ายการ “อธิบายโครงสร้างข้อมูล” มากกว่าการ “ไล่เช็กเงื่อนไข” ซึ่งอ่านง่ายมากเมื่อกลับมาดูภายหลัง

ตัวอย่างงานที่เหมาะกับ ts-pattern

ts-pattern เหมาะมากกับงานที่มี state หรือรูปแบบข้อมูลหลายชนิด เช่น

  • render UI ตาม state ของ API
  • จัดการ event หลายประเภท
  • แยก logic ตาม role ของ user
  • parse payload จาก webhook
  • ตรวจ action ของ reducer ใน state management
  • ระบบ dashboard, workflow, payment, permission และ event processing

ตัวอย่างแนวคิดแบบใกล้ตัว:

match(payment)
  • เจอ { status: 'paid' } → อนุมัติ
  • เจอ { status: 'pending' } → รอตรวจสอบ
  • เจอ { status: 'failed' } → แจ้งเตือน
  • ถ้าเขียนไม่ครบ → TypeScript เตือน

เมื่อ business logic มีหลายแขนง วิธีคิดแบบนี้จะช่วยให้แต่ละกรณีถูกระบุไว้อย่างชัดเจน และลดความคลุมเครือในโค้ดลงได้มาก

ช่วยลด bug เมื่อทีมขยายฟีเจอร์

อีกมุมหนึ่งที่สำคัญมากคือ ts-pattern ช่วยทีมรับมือกับการเปลี่ยนแปลงของระบบในระยะยาวได้ดี

ลองนึกภาพว่า วันนี้ระบบมี status แค่ success กับ error แต่เดือนหน้าทีมเพิ่ม archived เข้ามา หากยังใช้โค้ดที่ไม่มีการเช็กครบทุกกรณี บางจุดอาจลืมรองรับสถานะใหม่นี้ และ bug จะไปโผล่ตอน runtime

แต่ถ้าใช้ ts-pattern พร้อม exhaustive checking จุดที่ยังไม่รองรับ archived จะถูกเตือนทันทีตั้งแต่ตอนพัฒนา ทำให้ทีมแก้ไขได้เร็วและมั่นใจขึ้นมาก

นี่จึงเป็นเหตุผลที่หลายทีมเลือกใช้มันกับระบบที่มี business logic หนาแน่น เพราะการเปลี่ยนแปลงเล็ก ๆ ใน type สามารถส่งสัญญาณเตือนไปยังจุดที่ได้รับผลกระทบได้ทันที

เรื่อง performance ควรมองอย่างไร

ในแง่ performance โดยทั่วไป ts-pattern เหมาะกับงานแอปพลิเคชันทั่วไปได้สบาย จุดเด่นของมันไม่ใช่การรีดความเร็วแบบสุดขีด แต่คือการทำให้โค้ดชัดขึ้น ดูแลง่ายขึ้น และปลอดภัยขึ้นในระยะยาว

ดังนั้นถ้าบริบทของงานคือการพัฒนาแอปที่ต้องแก้ไขต่อเนื่อง มีหลาย state และมีทีมทำงานร่วมกัน ประโยชน์ด้านความอ่านง่ายและความมั่นใจในการ refactor มักคุ้มค่ามาก

วิธีเริ่มใช้แบบง่ายที่สุด

ถ้าอยากเริ่มต้นโดยไม่ต้องเปลี่ยนแนวทางทั้งโปรเจกต์ วิธีที่ง่ายที่สุดคือเริ่มจากจุดที่มี switch ยาว ๆ ก่อน โดยเฉพาะโค้ดที่ทำงานกับ union type ชัดเจน

แนวทางแนะนำ:

  1. หา switch หรือ if/else ที่มีหลายกรณี
  2. เลือกจุดที่มี state ชัดเจน เช่น loading | success | error | empty
  3. แทนที่ logic นั้นด้วยการ match
  4. ปิดท้ายด้วย .exhaustive() เพื่อให้ TypeScript ช่วยเช็กให้ครบ
  5. เมื่อเริ่มคุ้นแล้ว ค่อยขยับไปใช้กับ object pattern ที่ซับซ้อนขึ้น

สำหรับมือใหม่ ts-pattern อาจดูเป็นแนวคิดใหม่ในช่วงแรก แต่ถ้าคุ้นกับ object, union type และการแยก state อยู่แล้ว จะเรียนรู้ได้ค่อนข้างเร็ว

ส่วนสำหรับคนที่มีประสบการณ์ มันเป็นเครื่องมือที่ช่วยให้ TypeScript แสดงศักยภาพได้เต็มขึ้น โดยเฉพาะในเรื่อง type narrowing และ exhaustive checking

สรุป

ts-pattern เป็นตัวอย่างของไลบรารีเล็ก ๆ ที่สร้างผลลัพธ์ใหญ่ในงานประจำวันได้จริง มันช่วยให้โค้ดที่เต็มไปด้วยเงื่อนไขหลายแขนงกลายเป็นโค้ดที่ชัด กระชับ และปลอดภัยขึ้น โดยเฉพาะเมื่อทำงานกับ union type และ state ที่ซับซ้อน

หากคุณกำลังเจอกับ if/else ซ้อนหลายชั้น หรือ switch ที่ยาวจนเริ่มไม่มั่นใจว่าครบทุกกรณีหรือยัง ts-pattern คือเครื่องมือที่ควรลองอย่างยิ่ง เพราะบางครั้งสิ่งที่ช่วยทีมได้มากที่สุด ไม่ใช่ framework ขนาดใหญ่ แต่เป็นไลบรารีเล็ก ๆ ที่ทำให้โค้ดดีขึ้นทีละนิดในทุกวัน