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

The Compiler & Tooling

ทุกอย่างเรื่อง type ที่คุณเรียนมาถูกบังคับใช้โดยโปรแกรมเดียวคือ TypeScript compiler หรือ tsc แต่ tsc ทำงานสองอย่างที่ควรแยกออกจากกันในหัว — tsc check type ของคุณ และ emit JavaScript ออกมา setup สมัยใหม่มักแยกสองงานนี้ออกจากกัน: ให้ bundler emit JavaScript อย่างรวดเร็ว แล้วให้ tsc check type แยกต่างหาก

tsconfig.json คือที่ที่คุณตัดสินใจว่า checker จะเข้มแค่ไหน, จะ target JavaScript feature รุ่นไหน, module ถูก resolve อย่างไร และจะ emit อะไรออกมา (ถ้ามี) การตั้งไฟล์นี้ให้ถูกคือความต่างระหว่าง TypeScript ที่จับ bug ได้จริง กับ TypeScript ที่ปล่อย bug ผ่านไปเงียบ ๆ

บทเรียนสิ่งที่คุณจะได้เรียนรู้
tsconfig, deepflag ที่คุ้มค่าที่สุด — strict และครอบครัวของตัวเอง, target, module และ option ข้าง ๆ strict
Modules & resolutionESM เทียบ CJS และ tsc หาไฟล์ที่คุณ import เจอได้อย่างไร
Declaration files.d.ts คืออะไร, เขียนอย่างไร และ @types มาจากไหน
Build & emittsc เทียบ bundler, isolatedModules, type-only import และ project references
flowchart LR
  src["source .ts / .tsx"] --> tsc["tsc"]
  tsc -->|job 1| check["type-check
report errors"]
  tsc -->|job 2| emit["emit .js and .d.ts
(types erased)"]
  check --> ci["run in CI to catch bugs"]
  emit --> ship["run or bundle the JS"]
tsc ทำสองงานที่เป็นอิสระต่อกัน

แยกสองงานนี้ให้ชัดแล้วทั้ง toolchain จะเข้าใจง่ายขึ้น bundler อย่าง esbuild ทำงานที่ 2 ได้ในเสี้ยววินาที เพราะแค่ strip type ออกโดยไม่เข้าใจ type เลย — ซึ่งแปลว่าจะ emit code ที่ type-check ไม่ผ่านออกมาได้อย่างสบายใจ นั่นคือเหตุผลที่คำแนะนำมาตรฐานคือ: ให้ bundler emit แล้วรัน tsc --noEmit ใน CI เพื่อ check จริง ๆ ที่เหลือของโมดูลนี้จะแกะ config ที่ควบคุมทั้งสองงานนี้

TypeScript compiler ทำงานสองอย่างอะไร?
ทำไม bundler อย่าง esbuild ถึง emit JavaScript ที่ type-check ไม่ผ่านออกมาได้?
วิธีที่แนะนำในการจับ type error จริง ๆ เมื่อ bundler เป็นคน emit คืออะไร?