Why TypeScript?
bug ที่ TypeScript ถูกออกแบบมาเพื่อจับ
หัวข้อที่มีชื่อว่า “bug ที่ TypeScript ถูกออกแบบมาเพื่อจับ”นี่คือ JavaScript ธรรมดาที่ดูโอเคแต่พังตอน runtime:
function greet(user) { return "Hello, " + user.name.toUpperCase();}
greet({ nam: "Ada" }); // typo: `nam` not `name`// 💥 TypeError: Cannot read properties of undefined (reading 'toUpperCase')typo นี้จะไม่ถูกเจอจนกว่าบรรทัดนั้นจะรัน — อาจจะบน production, อาจจะเจอกับ user โชคร้ายคนหนึ่ง TypeScript ย้ายการค้นพบนั้นมาที่ compile time:
function greet(user: { name: string }) { return "Hello, " + user.name.toUpperCase();}
greet({ nam: "Ada" });// ❌ Error: Object literal may only specify known properties,// and 'nam' does not exist in type '{ name: string }'.คุณรู้ทันทีที่เขียน ใน editor ก่อนที่อะไรจะรัน การเปลี่ยนแปลงนั้น — จาก “พังทีหลัง ที่ไหนสักแห่ง” ไปเป็น “พังตอนนี้ ตรงนี้” — คือคุณค่าทั้งหมดของตัวเอง
compile time กับ runtime: เส้นแบ่งที่สำคัญ
หัวข้อที่มีชื่อว่า “compile time กับ runtime: เส้นแบ่งที่สำคัญ”TypeScript มีสอง phase ที่แยกกันสิ้นเชิง และการสับสนระหว่างสอง phase นี้คือต้นตอของความผิดพลาดของมือใหม่ส่วนใหญ่
flowchart LR ts[".ts source (type + logic)"] -->|tsc: type-check| check["Type checking (error รายงานตรงนี้)"] ts -->|tsc: emit| js[".js output (type ถูกลบ)"] js --> run["Runtime (ไม่มี type อยู่แล้ว)"]
- Compile time — type checker อ่าน annotation และ type ที่ infer ได้ของคุณ แล้วรายงาน error ความปลอดภัยทั้งหมดเกิดขึ้นตรงนี้
- Runtime — JavaScript ที่ emit ออกมารัน type หายไปหมดแล้ว เพราะถูกลบทิ้งตอน compile
นี่คือเหตุผลที่คุณทำแบบนี้ไม่ได้:
function isString(x: unknown) { return x is string; // ❌ not a thing — types don't exist at runtime}ตอน runtime ไม่มี type string ให้เช็ค — มีแต่ value ของ JavaScript การจะ narrow type ตอน runtime คุณต้องใช้ operation จริงของ JavaScript (typeof x === "string") ที่ compiler เข้าใจ เดี๋ยวเจาะลึกในบท narrowing
type erasure แบบเป็นรูปธรรม
หัวข้อที่มีชื่อว่า “type erasure แบบเป็นรูปธรรม”compile อันนี้:
interface User { name: string; age: number; }const u: User = { name: "Ada", age: 36 };function older(u: User): number { return u.age + 1; }JavaScript ที่ emit ออกมาคือ:
const u = { name: "Ada", age: 36 };function older(u) { return u.age + 1; }interface หายไปทั้งอัน annotation ถูกถอดออก type เพิ่ม runtime cost เท่ากับ ศูนย์ และไม่มีพฤติกรรมตอน runtime เลย — type คือบทสนทนาระหว่างคุณกับ compiler ที่จบก่อนโปรแกรมจะรัน
ต้นทุนที่ต้องยอมรับตามจริง
หัวข้อที่มีชื่อว่า “ต้นทุนที่ต้องยอมรับตามจริง”TypeScript ไม่ได้ฟรี และการแกล้งทำเป็นว่าฟรีก็ไม่ยุติธรรมกับคุณ:
- build step คุณต้องมี
tscหรือ bundler ที่ strip type ออก.tsธรรมดารันตรง ๆ ใน Node หรือ browser ไม่ได้ (แม้ว่า runtime หลายตัวจะเริ่มเพิ่มการ strip type เข้ามา) - learning curve type system เป็นภาษาในตัวเอง — คอร์สนี้ทั้งคอร์สมีอยู่ก็เพราะเหตุนี้
- ช่องว่างระหว่าง type กับ runtime compiler อาจ ผิด เรื่องความจริงตอน runtime ได้ —
any, cast ที่ผิด หรือ external data ที่ไม่ผ่านการ validate โกหก compiler ได้ type คือ model ไม่ใช่การการันตีเรื่องโลกภายนอก (โมดูล Practical Mastery พูดเรื่องนี้เป็นหลัก)
การแลกเปลี่ยนนี้เกือบจะคุ้มเสมอสำหรับอะไรก็ตามที่มากกว่า script ใช้แล้วทิ้ง: คุณจ่ายภาษีก้อนคงที่ แล้วได้ผลตอบแทนที่ทบต้นก้อนใหญ่กลับมาในรูปของ bug ที่ถูกจับ, การ refactor ที่ปลอดภัย และความฉลาดของ editor