TypeScript vs JavaScript – 6 พฤษภาคม 2569

จากความวุ่นวายสู่ความเป็นระเบียบ: ประสบการณ์จริงในการย้ายจาก JavaScript สู่ TypeScript

ย้อนกลับไปเมื่อ 5 ปีก่อน ในฐานะนักพัฒนาเว็บสาย Full-stack ผมเคยเป็นคนหนึ่งที่หลงรักในความอิสระของ JavaScript อย่างสุดหัวใจ ความสามารถในการเขียนโค้ดที่ยืดหยุ่น ไม่ต้องประกาศประเภทตัวแปรให้วุ่นวาย และการที่มันยอมให้เราทำอะไรก็ได้ตามใจสั่ง ทำให้ผมรู้สึกว่าการพัฒนาโปรเจกต์เป็นไปอย่างรวดเร็วและลื่นไหล แต่ทว่า เมื่อโปรเจกต์เริ่มขยายตัวจากโค้ดไม่กี่ร้อยบรรทัดกลายเป็นหลายหมื่นบรรทัด ความอิสระที่เคยหอมหวานกลับกลายเป็นฝันร้ายที่ตามหลอกหลอนผมในทุกๆ เช้าที่ต้องแก้บั๊ก

ปัญหาที่ผมเจอเป็นประจำคืออาการ “undefined is not a function” หรือการที่ส่งข้อมูลผิดประเภทเข้าไปในฟังก์ชันแล้วโปรแกรมพังกลางคันตอนรันไทม์ (Runtime Error) การไล่หาต้นตอของปัญหาในโปรเจกต์ JavaScript ขนาดใหญ่นั้นเหมือนกับการงมเข็มในมหาสมุทร เพราะเราไม่รู้เลยว่าตัวแปรที่ส่งต่อกันมาหลายทอดนั้นมีหน้าตาเป็นอย่างไรกันแน่ จนกระทั่งผมตัดสินใจเปิดใจลองใช้ TypeScript ซึ่งเป็นจุดเปลี่ยนสำคัญที่ทำให้มุมมองการเขียนโปรแกรมของผมเปลี่ยนไปตลอดกาล

1. เมื่อความยืดหยุ่นของ JavaScript กลายเป็นดาบสองคม

TypeScript vs JavaScript

Photo by Bibek ghosh on Pexels

ในโลกของ JavaScript ทุกอย่างดูง่ายไปหมด เราสามารถประกาศตัวแปร let data = 10; แล้วบรรทัดต่อมาเปลี่ยนมันเป็น data = "hello"; ได้ทันทีโดยที่ไม่มีใครห้าม ประสบการณ์ที่ผมเจอคือการทำงานในทีมที่มี Developer หลายคน แต่ละคนมีการตีความโครงสร้างข้อมูล (Data Structure) ต่างกัน เมื่อคนหนึ่งส่ง Object ที่มี Key ชื่อ user_id แต่อีกคนคาดหวัง userId ผลลัพธ์คือระบบพังโดยที่ไม่มีการแจ้งเตือนใดๆ ในขณะที่เขียนโค้ด

ความยืดหยุ่นนี้ทำให้เราขาด “สัญญา” (Contract) ระหว่างฟังก์ชัน การรีแฟกเตอร์โค้ด (Refactoring) กลายเป็นเรื่องน่ากลัว ทุกครั้งที่ผมต้องการเปลี่ยนชื่อฟิลด์ใน Database ผมต้องใช้คำสั่ง Find and Replace ทั่วทั้งโปรเจกต์ด้วยความหวาดระแวงว่าจะลืมเปลี่ยนจุดไหนไปหรือเปล่า ความกังวลนี้ทำให้ทีมเริ่มทำงานช้าลง เพราะเราเสียเวลาไปกับการเขียน Unit Test เพียงเพื่อเช็คว่าตัวแปรที่รับเข้ามานั้นมีค่าอยู่จริงหรือไม่

ปัญหา Runtime Error ที่แก้ไม่จบไม่สิ้น

หนึ่งในเหตุการณ์ที่จำได้แม่นคือการขึ้นระบบ Production แล้วเกิดข้อผิดพลาดที่หาที่มาไม่ได้เป็นชั่วโมง เพียงเพราะ API ส่งค่าตัวเลขกลับมาเป็น String แล้วฟังก์ชันคำนวณภาษีดันเอาไปบวกกันจนกลายเป็นข้อความต่อกัน (Concatenation) แทนที่จะเป็นการคำนวณทางคณิตศาสตร์ บั๊กแบบนี้จะไม่เกิดขึ้นเลยถ้าเรามีระบบที่ช่วยตรวจสอบประเภทข้อมูลตั้งแต่ตอนเขียน

2. TypeScript: ฮีโร่ผู้มาพร้อมกับความชัดเจน

การเริ่มต้นกับ TypeScript ในช่วงแรกอาจจะดูน่ารำคาญ เพราะคอมไพเลอร์จะคอยดุด่าเราตลอดเวลาว่า “คุณลืมกำหนด Type ตรงนี้” หรือ “ค่านี้อาจจะเป็น null ได้นะ” แต่พอผ่านไปสักพัก ผมเริ่มตระหนักว่า TypeScript ไม่ได้มาเพื่อขัดขวางเรา แต่มันมาเพื่อเป็น “เพื่อนคู่คิด” (Pair Programmer) ที่ช่วยเตือนเราก่อนที่จะทำอะไรผิดพลาด การมี Interface และ Type Definition ทำให้โค้ดของเรามีเอกสารกำกับอยู่ในตัว (Self-documenting)

ตัวอย่างที่ชัดเจนที่สุดคือการใช้ IntelliSense ใน VS Code เมื่อเราเปลี่ยนมาใช้ TypeScript ทันทีที่เราพิมพ์จุด (.) หลังชื่อ Object ตัว Editor จะแสดงรายการ Property และ Method ทั้งหมดที่สามารถใช้ได้พร้อมบอกประเภทข้อมูลอย่างชัดเจน ประสบการณ์นี้ทำให้ผมไม่ต้องสลับหน้าจอไปดูไฟล์ API Documentation บ่อยๆ อีกต่อไป ช่วยให้โฟกัสกับการแก้ปัญหา Logic ได้อย่างเต็มที่

การสร้างสัญญาที่แข็งแกร่งด้วย Interface

interface User {
  id: number;
  username: string;
  email: string;
  isAdmin?: boolean; // Optional property
}

function sendWelcomeEmail(user: User) {
  console.log(`Sending email to ${user.email}...`);
}

// หากเราส่ง Object ผิดโครงสร้าง TypeScript จะเตือนทันทีตั้งแต่นาทีที่เขียน
const newUser = { id: 1, name: "John" }; 
// Error: Argument of type '{ id: number; name: string; }' is not assignable to parameter of type 'User'.

3. การรีแฟกเตอร์ที่เคยน่ากลัว กลายเป็นเรื่องสนุก

สิ่งที่ผมชอบที่สุดหลังจากย้ายมา TypeScript คือความมั่นใจในการปรับปรุงโค้ด (Refactoring) เมื่อก่อนเวลาจะเปลี่ยนชื่อตัวแปรหรือโครงสร้าง Object ผมต้องภาวนาให้ Unit Test ครอบคลุมพอ แต่ใน TypeScript ผมแค่เปลี่ยนชื่อที่จุดประกาศ แล้วคอมไพเลอร์จะชี้เป้าให้ทันทีว่ามีจุดไหนในโปรเจกต์บ้างที่ได้รับผลกระทบและต้องแก้ไขตาม

เหตุการณ์หนึ่งที่ผมประทับใจคือตอนที่ต้องเปลี่ยนโครงสร้างข้อมูลของระบบตระกร้าสินค้าจาก Array ของ ID เป็น Array ของ Object ที่มีรายละเอียดมากขึ้น ผมใช้เวลาเพียงไม่กี่นาทีในการไล่แก้ตาม Error ที่ TypeScript บอก จนกระทั่ง Error ทั้งหมดหายไป ผมกดรันโปรแกรมและมันทำงานได้ถูกต้องในทันที ความรู้สึกมั่นใจแบบนี้เป็นสิ่งที่ JavaScript มอบให้ไม่ได้เลยในโปรเจกต์ขนาดใหญ่

ความปลอดภัยในการจัดการข้อมูลที่ซับซ้อน

นอกจากเรื่อง Type พื้นฐานแล้ว TypeScript ยังมีความสามารถขั้นสูงอย่าง Generic หรือ Union Types ที่ช่วยให้เราจัดการกับ Logic ที่ซับซ้อนได้โดยที่ยังรักษาความปลอดภัยของข้อมูลไว้ได้ เช่น การกำหนดสถานะของ Order ที่เป็นไปได้เฉพาะ ‘pending’ | ‘shipped’ | ‘delivered’ เท่านั้น ซึ่งช่วยป้องกันการใส่ค่าผิดพลาดได้อย่างเด็ดขาด

4. การทำงานร่วมกันในทีมที่ดีขึ้นอย่างเห็นได้ชัด

เมื่อทีมของเราขยายใหญ่ขึ้น การสื่อสารกลายเป็นเรื่องสำคัญที่สุด ในอดีตเวลาเพื่อนร่วมทีมเขียนฟังก์ชันใหม่ขึ้นมา ผมต้องเข้าไปอ่านโค้ดข้างในฟังก์ชันนั้นเพื่อดูว่าต้องส่ง Parameter อะไรเข้าไปบ้าง แต่พอมี TypeScript ผมแค่เอาเมาส์ไปวางที่ชื่อฟังก์ชัน ผมก็จะรู้ทันทีว่ามันต้องการอะไรและจะคืนค่าอะไรกลับมา นี่คือการสื่อสารผ่านโค้ดที่มีประสิทธิภาพที่สุด

นอกจากนี้ TypeScript ยังช่วยลดข้อพิพาทในตอน Code Review ได้มาก เพราะเรื่องพื้นฐานอย่างการส่งค่าผิดประเภทจะถูกดักไว้ตั้งแต่เครื่องของ Developer เอง หรืออย่างน้อยก็ในขั้นตอน CI/CD ทำให้การ Review โค้ดมุ่งเน้นไปที่เรื่องของ Business Logic และ Performance แทนที่จะมานั่งจับผิดเรื่องเล็กๆ น้อยๆ ที่เครื่องมือสามารถจัดการแทนเราได้

ลดภาระการเขียนเอกสาร

type ApiResponse<T> = {
  data: T;
  status: number;
  message: string;
};

interface Product {
  id: string;
  price: number;
}

// เราสามารถระบุได้ชัดเจนว่าฟังก์ชันนี้จะคืนค่า Product กลับมา
async function fetchProduct(id: string): Promise<ApiResponse<Product>> {
  const response = await fetch(`/api/products/${id}`);
  return response.json();
}

5. ข้อควรระวังและบทเรียนที่ได้รับจากการย้ายสาย

อย่างไรก็ตาม การย้ายจาก JavaScript มา TypeScript ไม่ได้มีแต่กลีบกุหลาบ ปัญหาแรกที่ทีมผมเจอคือ “Learning Curve” สำหรับคนที่คุ้นเคยกับความง่ายของ JS มาตลอด การต้องมาทำความเข้าใจเรื่อง Generics, Utility Types หรือการตั้งค่า tsconfig.json อาจทำให้รู้สึกท้อได้ในช่วงสัปดาห์แรกๆ นอกจากนี้ยังมีเรื่องของ “Any” ซึ่งเป็นกับดักที่อันตรายที่สุด หากเราใช้ any พร่ำเพรื่อ ความปลอดภัยที่ TypeScript มอบให้ก็จะหายไปทันที

อีกหนึ่งปัญหาคือการใช้ Library ภายนอกที่ไม่มี Type Definition มาให้ (แม้ว่าปัจจุบันส่วนใหญ่จะมีผ่าน @types แล้วก็ตาม) การต้องมานั่งเขียนไฟล์ .d.ts เองเป็นเรื่องที่น่าเบื่อและใช้เวลา แต่จากประสบการณ์ของผม การลงทุนลงแรงในช่วงแรกนั้นคุ้มค่ามหาศาลเมื่อเทียบกับเวลาที่เราต้องเสียไปกับการไล่แก้บั๊กในระยะยาว

สรุปประเด็นสำคัญ: TypeScript vs JavaScript

  • การตรวจจับข้อผิดพลาด: JavaScript ตรวจเจอตอนรัน (Runtime), TypeScript ตรวจเจอตอนเขียน (Compile-time)
  • ความเร็วในการพัฒนา: JavaScript เร็วในช่วงเริ่มโปรเจกต์, TypeScript เร็วกว่าในระยะยาวและการดูแลรักษา
  • เครื่องมือช่วยเขียน: TypeScript มี IntelliSense ที่แม่นยำกว่ามาก ช่วยลดการเปิด Documentation
  • การทำงานเป็นทีม: TypeScript ทำหน้าที่เป็นเอกสารในตัว ทำให้เข้าใจโค้ดของผู้อื่นได้ง่ายขึ้น
  • ความมั่นใจ: การรีแฟกเตอร์โค้ดใน TypeScript ปลอดภัยกว่าและลดความเสี่ยงที่ระบบจะพังโดยไม่รู้ตัว

สรุป

หากถามผมในวันนี้ว่าควรเลือกอะไรระหว่าง JavaScript และ TypeScript คำตอบของผมชัดเจนมากคือ “TypeScript สำหรับทุกโปรเจกต์ที่มีโอกาสจะเติบโต” แม้ว่ามันจะต้องการการตั้งค่าเพิ่มขึ้นเล็กน้อยและต้องเขียนโค้ดเยอะขึ้นอีกนิด แต่ความสงบสุขในการทำงานและความมั่นใจในคุณภาพของซอฟต์แวร์ที่ได้รับกลับมานั้นประเมินค่าไม่ได้

JavaScript ยังคงเป็นพื้นฐานที่สำคัญและยอดเยี่ยมสำหรับการเรียนรู้ แต่เมื่อคุณก้าวเข้าสู่การทำงานระดับมืออาชีพที่ต้องรับผิดชอบระบบขนาดใหญ่ TypeScript คือเครื่องมือที่จะเปลี่ยนคุณจากนักเขียนโค้ดธรรมดา ให้กลายเป็นวิศวกรซอฟต์แวร์ที่สร้างระบบที่แข็งแกร่งและยั่งยืนได้อย่างแท้จริง

Leave a Reply

Your email address will not be published. Required fields are marked *