ข้ามไปยังเนื้อหา

tsconfig, Deep

tsconfig.json มี option เป็นสิบ ๆ ตัว แต่มีไม่กี่ตัวที่ตัดสินว่า TypeScript ปกป้องคุณจริงหรือเปล่า ตัวสำคัญที่สุดคือ strict ไม่ใช่ check ตัวเดียว — แต่เป็นชุดที่เปิด flag ทั้งครอบครัวพร้อมกัน และทุกตัวจับ bug จริงได้

{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitOverride": true,
"verbatimModuleSyntax": true
}
}

เปิด strict ตั้งแต่วันแรก การมาเปิดทีหลังบน codebase ใหญ่ ๆ แปลว่าต้องแก้ error เป็นร้อยพร้อมกัน — ยากกว่าการไม่ปล่อยให้ error สะสมตั้งแต่แรกมาก

strict: true เป็นตัวย่อของครอบครัวนี้ทั้งหมด:

Flag (อยู่ใน strict)สิ่งที่จับได้
strictNullChecksnull และ undefined ไม่แอบอยู่ในทุก type อีกต่อไป — คุ้มที่สุด
noImplicitAnyvalue ที่จะ fall back เป็น any กลายเป็น error ที่คุณต้องแก้
strictFunctionTypesparameter ของ function ถูก check แบบ contravariant — callback ที่ไม่ปลอดภัยถูกจับ
strictBindCallApplybind, call และ apply ถูก type-check กับ signature ของ function
strictPropertyInitializationfield ของ class ต้องถูก assign ใน constructor (หรือ mark เป็น optional)
useUnknownInCatchVariablescatch (e) ให้ unknown ไม่ใช่ any บังคับให้คุณ narrow
alwaysStrictemit "use strict" และ parse ใน strict mode

พระเอกคือ strictNullChecks ถ้าไม่เปิด string จะแอบรวม null และ undefined ไว้ด้วย และ compiler เตือนคุณเรื่อง runtime crash ที่พบบ่อยที่สุดใน JavaScript ไม่ได้เลย พอเปิดแล้ว null และ undefined กลายเป็น type ของตัวเองที่คุณต้องจัดการอย่างตั้งใจ

สาม option นี้อธิบายโลกที่ code ของคุณรันอยู่:

  • target — JavaScript version ที่ tsc emit ออกมา ES2022 เป็น default สมัยใหม่ที่ปลอดภัย ถ้า target ต่ำกว่าจะ down-level syntax ใหม่ ๆ ให้เป็นของเทียบเท่าเวอร์ชันเก่า
  • module — module format ของ output (NodeNext, ESNext, CommonJS, …) ควรตรงกับวิธีที่ code ถูกโหลดจริง
  • lib — type declaration built-in ตัวไหนที่ใช้ได้ (เช่น DOM สำหรับ global ของ browser, ES2022 สำหรับ method ใหม่ ๆ ของ runtime) ถ้าคุณใช้ structuredClone หรือ Array.prototype.at ตัว lib ต้องรวมเวอร์ชันที่ declare API เหล่านั้นไว้

strict เป็นพื้น ไม่ใช่เพดาน อีกสอง flag จับ bug ที่ strict อย่างเดียวพลาด:

// noUncheckedIndexedAccess: true
const arr = [1, 2, 3];
const x = arr[10]; // type is now `number | undefined`, not `number`
x.toFixed(); // ❌ Object is possibly 'undefined' — exactly the bug you want caught
  • noUncheckedIndexedAccess — การ index array หรือ record อาจ return undefined ได้ (index 10 ของ array 3 ตัวก็ return) type จึงสะท้อนความจริงนั้น มีประสิทธิภาพมากในการกัน bug out-of-bounds
  • exactOptionalPropertyTypes — แยกความต่างระหว่าง property ที่ set เป็น undefined กับ property ที่หายไปเลย ทำให้ optional name?: string ไม่แอบรับ name: undefined อีกต่อไป
`strict: true` คืออะไร?
`strictNullChecks` เปลี่ยนอะไร?
เมื่อเปิด `noUncheckedIndexedAccess` แล้ว type ของ `arr[i]` สำหรับ `const arr: number[]` คืออะไร?
ทำไมควรเปิด `strict` ตั้งแต่เริ่มโปรเจกต์ ไม่ใช่มาเปิดทีหลัง?