Dark mode
การทำงานของ TypeScript
TypeScript ทำงานโดยเป็นเหมือน "ตัวเสริม" ให้กับ JavaScript ที่ช่วยในเรื่อง type safety โดยมีขั้นตอนการทำงานในรายละเอียดดังนี้
1. ขั้นตอนการพัฒนา (Development Time)
เมื่อคุณเขียนโค้ด TypeScript:
- การตรวจสอบแบบ Static Type: TypeScript จะตรวจสอบ type ทันทีขณะเขียนโค้ด ช่วยให้เห็นข้อผิดพลาดก่อนที่โค้ดจะถูกรัน เช่น หากคุณพยายามใช้เมธอดที่ไม่มีอยู่ในออบเจ็กต์ หรือส่งพารามิเตอร์ผิดประเภทให้กับฟังก์ชัน
- IDE สามารถให้คำแนะนำ: เนื่องจากมีข้อมูล type จึงทำให้ IDE เช่น VS Code สามารถให้คำแนะนำ (autocomplete) ที่เหมาะสม แสดงเฉพาะเมธอดและพร็อพเพอร์ตี้ที่มีอยู่จริงในออบเจ็กต์นั้นๆ ทำให้เขียนโค้ดได้เร็วขึ้นและลดข้อผิดพลาด
- ช่วยในการ Refactor: การเปลี่ยนแปลงโค้ดทำได้ปลอดภัยขึ้นเพราะ TypeScript จะแจ้งเตือนเมื่อมีการเปลี่ยนแปลงที่อาจก่อให้เกิดข้อผิดพลาด เช่น การเปลี่ยนชื่อฟังก์ชัน หรือเปลี่ยนโครงสร้างอินเตอร์เฟซ จะมีการแจ้งเตือนทุกจุดที่ต้องแก้ไขตาม
- การตรวจสอบความสมบูรณ์: TypeScript ช่วยตรวจสอบว่าคุณได้จัดการกับทุกกรณีที่เป็นไปได้หรือไม่ เช่น เมื่อใช้ union types หรือ enum ทำให้ไม่พลาดการจัดการกับบางกรณี
2. การคอมไพล์ (Compilation Time)
เมื่อคุณคอมไพล์โค้ด TypeScript:
- การตรวจสอบ Type อีกครั้ง: TypeScript Compiler (
tsc
) ตรวจสอบความถูกต้องของ type ทั้งหมดทั่วทั้งโปรเจ็กต์ ตรวจสอบความสอดคล้องระหว่างไฟล์ต่างๆ และแจ้งเตือนหากมีข้อผิดพลาด - การแปลงโค้ด (Type Erasure): TypeScript ถูกแปลงเป็น JavaScript ล้วนๆ โดยลบข้อมูล type ทั้งหมดออก เช่น type annotations, interfaces, generics จะถูกลบออกทั้งหมด เหลือเพียงโครงสร้างโค้ดที่ทำงานได้
- การ Downlevel: คุณสามารถเลือกว่าต้องการให้ JavaScript ที่ได้เป็นเวอร์ชันใด (ES5, ES6, ES2020 ฯลฯ) ตามความต้องการ โดยกำหนดผ่าน
target
ในtsconfig.json
ช่วยให้โค้ดทำงานได้บนเบราว์เซอร์เก่าหรือสภาพแวดล้อมที่จำกัด - การแปลง Syntax ขั้นสูง: ฟีเจอร์ขั้นสูงของ TypeScript เช่น decorators, optional chaining, nullish coalescing จะถูกแปลงเป็นโค้ด JavaScript ที่ทำงานเทียบเท่ากัน
ตัวอย่างการแปลงโค้ด:
ts
// โค้ด TypeScript
interface Person {
name: string;
age: number;
}
function greet(person: Person): string {
return `Hello, ${person.name}! You are ${person.age} years old.`;
}
const user: Person = {
name: "John",
age: 30
};
console.log(greet(user));
จะถูกแปลงเป็น:
js
// โค้ด JavaScript หลังการ transpile
function greet(person) {
return "Hello, " + person.name + "! You are " + person.age + " years old.";
}
const user = {
name: "John",
age: 30
};
console.log(greet(user));
สังเกตว่า interface และ type annotations ทั้งหมดหายไป เหลือเพียงโค้ดที่ทำงานได้จริง
3. ในช่วงรันไทม์ (Runtime)
- TypeScript หายไปหมด: ในช่วงรันไทม์ไม่มี TypeScript เหลืออยู่เลย เพราะเบราว์เซอร์และ Node.js รัน JavaScript เท่านั้น ทำให้ไม่มีโอเวอร์เฮดจากการตรวจสอบ type
- ไม่มีการตรวจสอบ Type: การตรวจสอบ type ทั้งหมดทำเสร็จสิ้นแล้วในขั้นตอนก่อนหน้า ดังนั้นในรันไทม์จึงไม่มีการตรวจสอบ type อีก หากมีข้อผิดพลาดที่ไม่ถูกตรวจพบในช่วงคอมไพล์ ก็จะเกิดขึ้นในรันไทม์เหมือน JavaScript ทั่วไป
- ประสิทธิภาพเทียบเท่า JavaScript: เนื่องจากโค้ดที่รันเป็น JavaScript ล้วนๆ จึงมีประสิทธิภาพเทียบเท่ากับการเขียน JavaScript โดยตรง ไม่มีการเสียประสิทธิภาพจากการตรวจสอบ type
4. เครื่องมือและการทำงานเพิ่มเติม
tsconfig.json: ไฟล์นี้ใช้กำหนดการตั้งค่าการคอมไพล์ เช่น:
target
: กำหนดเวอร์ชัน JavaScript ที่ต้องการเป็นผลลัพธ์module
: กำหนดระบบโมดูลที่ใช้ (CommonJS, ESM, AMD)strict
: เปิดการตรวจสอบ type แบบเข้มงวดlib
: กำหนดไลบรารีมาตรฐานที่ต้องการใช้outDir
: กำหนดโฟลเดอร์สำหรับไฟล์ JavaScript ที่คอมไพล์แล้ว
ไฟล์ Declaration (.d.ts): ไฟล์เหล่านี้อธิบาย type ของโค้ด JavaScript เพื่อให้ TypeScript เข้าใจได้ โดยไม่มีโค้ดการทำงานจริง เป็นเพียงการประกาศ type เท่านั้น ช่วยให้สามารถใช้ไลบรารี JavaScript กับ TypeScript ได้
Type Definition (@types): ไลบรารี JavaScript มักมี type definition แยกต่างหาก เช่น
@types/react
ซึ่งสามารถติดตั้งผ่าน npm เพื่อให้ TypeScript เข้าใจไลบรารีนั้นๆ โดยไม่ต้องเขียน type definition เองType Assertion: ในบางกรณีที่ TypeScript ไม่สามารถระบุ type ได้อย่างถูกต้อง คุณสามารถใช้ type assertion เพื่อบอก TypeScript ว่าตัวแปรมี type อะไร เช่น
const elem = document.getElementById('app') as HTMLElement
Generics: เป็นเครื่องมือที่ทรงพลังใน TypeScript ที่ช่วยให้สามารถสร้างฟังก์ชันหรือคลาสที่ทำงานกับหลาย type ได้ แต่ยังคงรักษาความปลอดภัยของ type
5. ข้อดีของกระบวนการนี้
- Zero Runtime Overhead: เนื่องจาก TypeScript ถูกแปลงเป็น JavaScript ล้วนๆ จึงไม่มี overhead ในช่วงรันไทม์ ไม่มีการเพิ่มขนาดไฟล์หรือลดประสิทธิภาพเมื่อเทียบกับ JavaScript โดยตรง
- ความปลอดภัยในการพัฒนา: ได้ประโยชน์จากการตรวจสอบ type โดยไม่กระทบประสิทธิภาพเมื่อรันจริง ช่วยลดข้อผิดพลาดที่พบบ่อยใน JavaScript เช่น undefined is not a function, cannot read property of undefined
- ใช้ร่วมกับ JavaScript เดิมได้: สามารถนำ TypeScript ไปใช้ในโครงการ JavaScript เดิมได้ทีละส่วน โดยการเปลี่ยนนามสกุลไฟล์จาก .js เป็น .ts และค่อยๆ เพิ่ม type annotation ทีหลัง ไม่จำเป็นต้องแปลงทั้งโปรเจ็กต์ในครั้งเดียว
- การทำงานร่วมกับทีม: ช่วยให้ทีมพัฒนาเข้าใจโค้ดได้ง่ายขึ้น เพราะมี type ที่ชัดเจน ทำให้ทำงานร่วมกันได้ดีขึ้น โดยเฉพาะในโปรเจ็กต์ขนาดใหญ่
- การบำรุงรักษาโค้ดระยะยาว: ช่วยให้การแก้ไขและปรับปรุงโค้ดในอนาคตทำได้ง่ายขึ้น เพราะ TypeScript จะช่วยตรวจสอบว่าการเปลี่ยนแปลงไม่ทำให้โค้ดส่วนอื่นเสียหาย
โดยสรุป TypeScript ทำหน้าที่เป็น "คนตรวจสอบความปลอดภัย" ในช่วงพัฒนาและคอมไพล์ แต่เมื่อถึงเวลารันจริง มันจะกลายเป็น JavaScript ธรรมดาที่มีประสิทธิภาพเทียบเท่ากับการเขียน JavaScript โดยตรง แต่มีความปลอดภัยด้าน type มากกว่า ทำให้ได้ประโยชน์ทั้งสองทาง คือความปลอดภัยในการพัฒนาและประสิทธิภาพในการทำงานจริง