TypeScript 7’s new Go-based compiler, tsgo, กำลังทำให้เครื่องมือพัฒนาที่ได้รับความนิยมอย่าง ESLint, ts-jest และ ts-morph ใช้งานไม่ได้แล้ว ปัญหาการใช้งานไม่ได้นี้จะยังคงดำเนินต่อไปจนกว่า programmatic API ของคอมไพเลอร์จะมีความเสถียรในการเปิดตัวเวอร์ชัน 7.1 ที่กำลังจะมาถึง ซึ่งหมายความว่าทีมที่ต้องพึ่งพาเครื่องมือเหล่านี้ควรระงับแผนการอัปเกรดไว้ก่อน
มีอะไรเปลี่ยนไปใน TypeScript 7
การเปิดตัวครั้งนี้ได้นำเสนอ tsgo ซึ่งเป็นการพอร์ตตัวตรวจสอบประเภท (type-checker) มาเป็นภาษา Go โดยทีม TypeScript ใช้รหัสลับว่า Project Corsa ด้วยการย้ายแกนหลักจาก JavaScript มาเป็น Go ทำให้คอมไพเลอร์สามารถประมวลผล build ได้เร็วขึ้นถึงสิบเท่า ซึ่งเป็นจุดเด่นที่ดึงดูดผู้ใช้งานกลุ่มแรกที่ต้องการลดเวลาใน CI pipelines ลงได้หลายนาที
ทำไมเครื่องมือต่างๆ ถึงทำงานผิดพลาด
เครื่องมือที่ทำงานร่วมกับ TypeScript ไม่ได้สื่อสารกับ type-checker โดยตรง แต่จะเรียกใช้ชุด internal API ที่เปิดเผยข้อมูลประเภท (type information), การวินิจฉัย (diagnostics) และการท่องโครงสร้าง AST (AST traversal) ซึ่ง API เหล่านี้ถูกเขียนขึ้นใหม่สำหรับ tsgo และยังคงมีการเปลี่ยนแปลงอยู่จนกว่าจะถึงเวอร์ชัน 7.1 ส่งผลให้เกิดความล้มเหลวต่อเนื่อง ทั้งแบบที่โปรแกรมหยุดทำงาน (crash) และแบบที่ทำงานผิดพลาดโดยไม่แจ้งเตือน (silent failure):
- typescript-eslint – npm ปฏิเสธที่จะติดตั้งร่วมกับ TypeScript 7 หากฝืนติดตั้งจะทำให้ ESLint แสดงข้อผิดพลาด
TypeError - ts-jest – พยายามเรียกใช้ internal methods ที่ไม่มีอยู่ในเวอร์ชัน Go แล้ว ส่งผลให้การแปลงไฟล์ทดสอบ (test-file transformation) หยุดทำงาน
- ts-morph – คาดหวังว่าจะใช้ stable API ในการไล่ดูโครงสร้างโค้ด แต่ด้วย API ปัจจุบัน มันอาจคืนค่าผลลัพธ์ที่ผิดพลาดหรือล้มเหลวโดยไม่มีการแจ้งเตือน
- Monorepos – tsgo ตัด generic type parameters บางตัวออกไป นำไปสู่ข้อผิดพลาดด้านประเภท (type errors) ที่จะปรากฏเฉพาะในโปรเจกต์ขนาดใหญ่ที่มีหลายแพ็กเกจเท่านั้น
เวิร์กโฟลว์ใดก็ตามที่มีการใช้ linting, การทดสอบด้วย Jest หรือการวิเคราะห์โค้ดร่วมกับ TypeScript 7 มีแนวโน้มที่จะพบกับ build ล้มเหลว (red builds)
ใครบ้างที่ได้รับผลกระทบ
- ทีม Front-end ที่รัน ESLint เป็นส่วนหนึ่งของทุก pull request
- บริการ Back-end ที่พึ่งพา ts-jest สำหรับการทำ unit testing
- ไลบรารีที่ใช้ ts-morph สำหรับการสร้างโค้ด (code generation) หรือการทำเอกสาร (documentation)
- องค์กรที่มีการตั้งค่าแบบ monorepo ซึ่งการอนุมานประเภท (type inference) มีความซับซ้อนอยู่แล้ว
หาก CI pipeline ของคุณกลายเป็นสีแดง (ล้มเหลว) หลังจากอัปเกรด TypeScript สาเหตุน่าจะเป็นหนึ่งในข้อข้างต้น
แนวทางการย้ายเวอร์ชันอย่างปลอดภัยจนกว่าจะถึง 7.1
วิธีที่ง่ายที่สุดในการรักษาความเร็วที่เพิ่มขึ้นโดยไม่ทำให้เครื่องมือพัง คือการแยกขั้นตอนการตรวจสอบประเภทที่รวดเร็วออกจากขั้นตอนการ build จริง:
- ตรึงเวอร์ชันหลักของ TypeScript ไว้ที่ 6.x – เพื่อรักษา stable API ที่เครื่องมือทั้งหมดคาดหวังไว้
- เพิ่ม
@typescript/native-previewเป็น dev dependency – แพ็กเกจนี้จะมาพร้อมกับไฟล์ binary ของ tsgo เพื่อใช้ตรวจสอบประเภทอย่างรวดเร็วใน CI - รัน tsgo ด้วย
--noEmitเพื่อการตรวจสอบที่รวดเร็ว – ซึ่งจะตรวจสอบความถูกต้องของประเภทแต่จะไม่สร้างไฟล์ output ออกมา - ใช้คอมไพเลอร์
tscแบบดั้งเดิมสำหรับการ build จริง – เนื่องจากtscยังคงสร้าง JavaScript และรองรับ API ของเวอร์ชัน 6.x
npm install -D typescript@^6.9
npm install -D @typescript/native-preview
อัปเดตสคริปต์ใน package.json ของคุณ:
{
"scripts": {
"typecheck:fast": "tsgo --noEmit",
"build": "tsc"
}
}
ด้วยการตั้งค่าแบบคู่ขนานนี้ คุณจะยังคงได้รับความเร็วที่เพิ่มขึ้นถึงสิบเท่าใน CI ในขณะที่ยังรักษาความเข้ากันได้กับ ESLint, ts-jest และ ts-morph ไว้ได้
เมื่อไหร่ที่คุณสามารถอัปเกรดเป็น 7.0 ได้ทันที
หากโค้ดของคุณมีการเรียกใช้เพียงแค่ tsc เท่านั้น โดยไม่มีการทำ linting, ไม่มี Jest หรือ ts-morph API ที่ไม่เสถียรก็จะไม่ส่งผลกระทบต่อคุณ ในกรณีเฉพาะเช่นนี้ คุณสามารถย้ายไปใช้ TypeScript 7 ได้ทันทีและเพลิดเพลินกับประสิทธิภาพที่เพิ่มขึ้นโดยไม่ต้องมีขั้นตอนเพิ่มเติม
สิ่งที่ควรเฝ้าระวัง
- เวอร์ชัน 7.1 – ทีม TypeScript ได้ส่งสัญญาณว่า programmatic API จะถูกกำหนดให้คงที่ (frozen) ในการเปิดตัวครั้งนี้ เมื่อเวอร์ชันนี้มาถึง ตัวเชื่อมระหว่าง tsgo และเครื่องมือที่มีอยู่เดิมจะหายไป ทำให้สามารถอัปเกรดได้อย่างราบรื่น
- การอัปเดตเครื่องมือต่างๆ – คอยติดตามการเปิดตัวเวอร์ชันใหม่ของ
typescript-eslint,ts-jestและts-morphซึ่งพวกเขาจะปล่อยเวอร์ชันที่รองรับออกมาในเวลาไม่นานหลังจาก 7.1 เปิดตัว - การตั้งค่า CI – อย่าลืมเปลี่ยนจาก
tsgo --noEmitกลับมาเป็นการเรียกใช้tscปกติเมื่อ API มีความเสถียรแล้ว และจะไม่จำเป็นต้องใช้แพ็กเกจ preview อีกต่อไป
สรุป: จนกว่า API ในเวอร์ชัน 7.1 จะถูกกำหนดให้คงที่ ให้ใช้ TypeScript 6.x เป็นคอมไพเลอร์หลักของคุณ, เพิ่ม @typescript/native-preview เพื่อการตรวจสอบที่รวดเร็ว และใช้ tsc ต่อไปสำหรับการ build วิธีนี้จะช่วยหลีกเลี่ยงปัญหา linting และการทดสอบที่พัง ในขณะที่ยังได้รับประโยชน์ด้านประสิทธิภาพจากเอนจินภาษา Go ตัวใหม่
