ประกาศ TypeScript 6.0
(devblogs.microsoft.com)- เป็นทั้ง รีลีสสุดท้าย ของโค้ดเบสปัจจุบันที่พัฒนาบน JavaScript และเป็น รีลีสสะพานเชื่อม เพื่อเตรียมเปลี่ยนผ่านไปสู่ TypeScript 7.0 ซึ่งเป็นเนทีฟพอร์ตที่เขียนด้วย Go
- รวมการปรับปรุงด้านการอนุมานชนิดและการตีความโมดูล เช่น ผ่อนปรนความไวต่อบริบท ของฟังก์ชันที่ไม่ได้ใช้
thisและรองรับ subpath imports ที่ขึ้นต้นด้วย#/ - ปรับค่าเริ่มต้นของตัวเลือกคอมไพเลอร์ให้ทันสมัยครั้งใหญ่ เช่น เปลี่ยนค่าเริ่มต้น
strictเป็นtrue, ค่าเริ่มต้นtargetเป็นes2025, และค่าเริ่มต้นtypesเป็น[] - เลิกใช้ตัวเลือกแบบ legacy จำนวนมาก เช่นเป้าหมาย ES5, โมดูล AMD/UMD/SystemJS,
--baseUrl,--moduleResolution node10เป็นต้น - เพิ่ม การรองรับชนิดสำหรับข้อเสนอ ECMAScript Stage 4 ล่าสุด เช่น Temporal API,
getOrInsert/getOrInsertComputedของ Map และRegExp.escape
ตำแหน่งของ TypeScript 6.0
- เป็น รีลีสสุดท้าย บนโค้ดเบส JavaScript ปัจจุบัน และทำหน้าที่เป็นสะพานสำหรับการเปลี่ยนผ่านไปยัง TypeScript 7.0 (เนทีฟพอร์ตด้วย Go)
- TypeScript 7.0 ใช้ประโยชน์จาก เนทีฟโค้ดและมัลติเธรดแบบ shared memory และตอนนี้ใกล้เสร็จสมบูรณ์มากแล้ว
- การเปลี่ยนแปลงส่วนใหญ่ใน 6.0 มีไว้เพื่อ ปรับแนวทางและเตรียมพร้อม สำหรับการนำ 7.0 มาใช้
- สามารถทดลอง TypeScript 7.0 ล่วงหน้าได้ผ่าน ส่วนขยาย VS Code หรือ แพ็กเกจ npm
การเปลี่ยนแปลงหลัง Beta และ RC
- ปรับการตรวจสอบชนิดของ function expression ในการเรียกแบบ generic (โดยเฉพาะ generic JSX expression) — ช่วยจับบั๊กในโค้ดเดิมได้มากขึ้น แต่อาจทำให้บาง generic call ต้องระบุ type argument อย่างชัดเจน
- ขยายการเลิกใช้ ไวยากรณ์ import assertion (
assert) ให้ครอบคลุมถึงการเรียกimport()ด้วย - อัปเดต DOM types — สะท้อนมาตรฐานเว็บล่าสุด รวมถึงการปรับที่เกี่ยวข้องกับ Temporal API
ผ่อนปรนความไวต่อบริบทของฟังก์ชันที่ไม่ได้ใช้ this
- ระหว่างการอนุมานชนิด TypeScript จะจัดฟังก์ชันที่มีพารามิเตอร์ไม่มีชนิดระบุชัดเจนให้เป็น ฟังก์ชันไวต่อบริบท (contextually sensitive function) และประมวลผลลำดับหลัง
- ฟังก์ชันที่เขียนด้วย method syntax จะมีพารามิเตอร์
thisโดยนัย ทำให้ ต่างจาก arrow function ตรงที่ถูกถือว่าไวต่อบริบทเสมอ- ส่งผลให้บางครั้งการอนุมานชนิดล้มเหลวตามลำดับของเมธอดภายใน object literal
- ใน TypeScript 6.0 ฟังก์ชันที่ไม่ได้ใช้
thisจริง ๆ จะไม่ถูกมองว่าไวต่อบริบทอีกต่อไป- ฟังก์ชันเหล่านี้จึงได้ ลำดับความสำคัญสูงขึ้นในการอนุมานชนิด และอนุมานได้ถูกต้องโดยไม่ขึ้นกับลำดับของเมธอด
- พัฒนาจาก ผลงาน ของ Mateusz Burzyński
รองรับ Subpath Imports ที่ขึ้นต้นด้วย #/
- ฟีเจอร์ subpath imports ของ Node.js คือการกำหนด alias ให้โมดูลภายในแพ็กเกจผ่านฟิลด์
importsในpackage.json - ก่อนหน้านี้จำเป็นต้องมีอักขระหลัง
#เสมอ จึงไม่สามารถใช้พาธที่ขึ้นต้นด้วย#/ได้- ทำให้นักพัฒนาที่คุ้นกับคอนเวนชันคำนำหน้า
@/ของ bundler สับสน
- ทำให้นักพัฒนาที่คุ้นกับคอนเวนชันคำนำหน้า
- ล่าสุด Node.js เริ่มรองรับ subpath imports ที่ขึ้นต้นด้วย
#/- ทำให้แมปแบบกระชับในรูป
"#/*": "./dist/*"ได้
- ทำให้แมปแบบกระชับในรูป
- TypeScript 6.0 รองรับสิ่งนี้ในตัวเลือก
--moduleResolution nodenextและbundler - พัฒนาจาก ผลงาน ของ magic-akari
อนุญาตให้ใช้ --moduleResolution bundler ร่วมกับ --module commonjs
- เดิมที
--moduleResolution bundlerใช้ได้เฉพาะกับ--module esnextหรือ--module preserve - จากการเลิกใช้
--moduleResolution node(node10) ทำให้ ชุดค่าผสมใหม่นี้เป็นเส้นทางอัปเกรดที่เหมาะสมที่สุดสำหรับหลายโปรเจกต์ - ในระยะยาวแนะนำให้ย้ายไปใช้
--module preserve+--moduleResolution bundlerหรือ--module nodenext
แฟล็ก --stableTypeOrdering
- type ID ที่ TypeScript กำหนดให้ชนิดภายในจะขึ้นกับลำดับการประมวลผล และใช้สิ่งนี้ในการจัดเรียง union type
- จึงอาจเกิดพฤติกรรมคาดเดายากที่ ผลลัพธ์ declaration emit เปลี่ยนไปตามลำดับการประกาศ
- TypeScript 7.0 จะเพิ่ม การตรวจสอบชนิดแบบขนาน จึงใช้ อัลกอริทึมจัดเรียงแบบกำหนดแน่นอนตามเนื้อหา เพื่อแก้ปัญหา ID ที่ไม่แน่นอน
- เช่น
100 | 500จะถูกพิมพ์ออกมาในลำดับเดิมเสมอ
- เช่น
- หากเปิดแฟล็ก
--stableTypeOrderingใน 6.0 จะทำให้ พฤติกรรมการจัดเรียงชนิดตรงกับ 7.0 และลดความต่างระหว่างสองโค้ดเบส- อาจทำให้ ประสิทธิภาพลดลงได้สูงสุด 25% ในการตรวจสอบชนิด
- หากเกิด type error จากความต่างในการอนุมาน สามารถแก้ได้ด้วยการเพิ่ม type argument หรือ variable annotation แบบชัดเจน
- แฟล็กนี้มีไว้ เพื่อวินิจฉัยการย้ายจาก 6.0 ไป 7.0 เท่านั้น ไม่แนะนำให้ใช้ระยะยาว
ตัวเลือก es2025 (target และ lib)
- ES2025 ไม่มีฟีเจอร์ภาษา JavaScript ใหม่ แต่เพิ่ม ชนิดของ built-in API (เช่น
RegExp.escape) Promise.try, เมธอดของIterator, และเมธอดของSetที่เดิมอยู่ในesnextถูก ย้ายไปยังes2025- พัฒนาจาก ผลงาน ของ Kenta Moriuchi
รองรับชนิดของ Temporal API
- รวม built-in type ของ ข้อเสนอ Temporal ที่ไปถึง Stage 4 แล้วไว้ใน TypeScript 6.0
- ใช้งานได้ด้วย
--target esnextหรือ"lib": ["esnext"](หรือแบบแยกละเอียดesnext.temporal) - ใช้ API อย่าง
Temporal.Now.instant().subtract()และ.add()ได้อย่างปลอดภัยด้านชนิด - ตอนนี้ใช้งานได้แล้วในหลาย runtime และด้วยการไปถึง Stage 4 จึงเป็น ส่วนหนึ่งของภาษา JavaScript อย่างเป็นทางการ
- พัฒนาจาก ผลงาน ของ Renegade334
รองรับชนิดของเมธอด "upsert" ใน Map (getOrInsert / getOrInsertComputed)
- ทำให้แพตเทิร์นซ้ำ ๆ ในการตรวจสอบว่าคีย์มีอยู่ใน Map หรือไม่ และกำหนดค่าเริ่มต้นเมื่อไม่มี สั้นลง
- ข้อเสนอ "upsert" ของ ECMAScript ไปถึง Stage 4 แล้ว จึงเพิ่มเมธอดใหม่ 2 ตัวใน
MapและWeakMapgetOrInsert: ถ้าไม่มีคีย์ จะใส่ค่าเริ่มต้นที่กำหนดแล้วคืนค่านั้นgetOrInsertComputed: หากการสร้างค่าเริ่มต้นมีต้นทุนสูง สามารถคำนวณแบบ lazy ผ่าน callback ได้- callback รับคีย์เป็นอาร์กิวเมนต์ จึงใช้สร้างค่าเริ่มต้นตามคีย์ได้ด้วย
- ถูกเพิ่มใน lib
esnextและใช้งานได้ทันทีใน TypeScript 6.0 - พัฒนาจาก ผลงาน ของ Renegade334
RegExp.escape
- ฟังก์ชัน
RegExp.escapeสำหรับ escape อักขระพิเศษใน regular expression ไปถึง Stage 4 แล้ว - รวมอยู่ใน lib
es2025และใช้งานได้ใน TypeScript 6.0 - พัฒนาจาก ผลงาน ของ Kenta Moriuchi
รวม dom.iterable และ dom.asynciterable เข้ากับ lib dom
- เดิมหากต้องการใช้ iteration กับ
NodeList,HTMLCollectionเป็นต้น จำเป็นต้องระบุ"lib": ["dom", "dom.iterable"] - ใน TypeScript 6.0 เนื้อหาของ
lib.dom.iterable.d.tsและlib.dom.asynciterable.d.tsถูก รวมเข้ากับlib.dom.d.tsอย่างสมบูรณ์dom.iterableและdom.asynciterableยังอ้างอิงได้ แต่เป็น ไฟล์ว่าง
- เบราว์เซอร์สมัยใหม่หลักทั้งหมดรองรับฟีเจอร์นี้อยู่แล้ว จึงเป็น การปรับปรุงด้านความสะดวก เพื่อลดจุดที่ทำให้สับสนบ่อย
การเปลี่ยนค่าเริ่มต้นสำคัญ
- ค่าเริ่มต้น
strictเป็นtrue: โปรเจกต์ใหม่ส่วนใหญ่มักต้องการ strict mode ดังนั้นโปรเจกต์ที่เคยพึ่งพาfalseต้องตั้ง"strict": falseเองอย่างชัดเจน - ค่าเริ่มต้น
moduleเป็นesnext: สะท้อนความจริงที่ว่า ESM กลายเป็นรูปแบบโมดูลหลักแล้ว - ค่าเริ่มต้น
targetเป็นเวอร์ชัน ES ล่าสุด (ปัจจุบันคือes2025): runtime แบบ evergreen แพร่หลายจนไม่จำเป็นต้อง transpile ไปเวอร์ชันเก่า - ค่าเริ่มต้น
noUncheckedSideEffectImportsเป็นtrue: ช่วยตรวจจับการพิมพ์ผิดใน import ที่มีไว้เพื่อ side effect เท่านั้น - ค่าเริ่มต้น
libReplacementเป็นfalse: ป้องกันความล้มเหลวในการ resolve โมดูลโดยไม่จำเป็นและลดจำนวนไฟล์ที่ต้องเฝ้าดู จึงช่วยเพิ่มประสิทธิภาพพื้นฐาน
เปลี่ยนค่าเริ่มต้น rootDir เป็น .
- เดิมหากไม่ระบุ ระบบจะอนุมานจาก ไดเรกทอรีร่วม ของไฟล์ input ที่ไม่ใช่ declaration ทั้งหมด
- ทำให้การตัดสินว่าไฟล์ใดอยู่ในโปรเจกต์ต้องโหลดและ parse โปรเจกต์นั้นก่อน
- ใน TypeScript 6.0 ค่าเริ่มต้นถูกกำหนดตายตัวเป็น ไดเรกทอรีที่มี
tsconfig.jsonอยู่ - หากไฟล์ซอร์สอยู่ลึกกว่า
tsconfig.jsonจำเป็นต้องตั้งค่า"rootDir": "./src"เป็นต้นอย่างชัดเจน- ถ้าไม่ตั้ง อาจได้โครงสร้างผลลัพธ์ที่ไม่ตั้งใจ เช่น
./dist/src/index.js
- ถ้าไม่ตั้ง อาจได้โครงสร้างผลลัพธ์ที่ไม่ตั้งใจ เช่น
เปลี่ยนค่าเริ่มต้น types เป็น []
- เดิมจะรวม ทุกแพ็กเกจ ใน
node_modules/@typesโดยอัตโนมัติ ทำให้เกิด overhead สูงมากในเวลา build- ในรีโพซิทอรีทั่วไป มักมีแพ็กเกจ
@typesหลายร้อยตัวถูกดึงเข้ามาแบบ transitive
- ในรีโพซิทอรีทั่วไป มักมีแพ็กเกจ
- TypeScript 6.0 จึงเปลี่ยนค่าเริ่มต้นเป็น
[](อาร์เรย์ว่าง) เพื่อป้องกันการโหลด declaration file ที่ไม่จำเป็น - พบกรณีจริงที่ เวลา build ดีขึ้น 20–50%
- โปรเจกต์ส่วนใหญ่จะต้องตั้งค่าอย่างชัดเจน เช่น
"types": ["node"]หรือ"types": ["node", "jest"]- สามารถคืนพฤติกรรมเดิมได้ด้วย
"types": ["*"]
- สามารถคืนพฤติกรรมเดิมได้ด้วย
รายการที่เลิกใช้ (Deprecation)
เลิกใช้ target: es5
- เป้าหมาย ES5 แทบไม่มีกรณีใช้งานแล้ว จากการปลดระวาง IE และการแพร่หลายของเบราว์เซอร์แบบ evergreen
- เป้าหมายขั้นต่ำเปลี่ยนเป็น ES2015 และหากยังต้องการผลลัพธ์แบบ ES5 แนะนำให้ใช้คอมไพเลอร์ภายนอก
เลิกใช้ --downlevelIteration
- มีผลเฉพาะกับการ emit แบบ ES5 เท่านั้น ดังนั้นเมื่อเลิกใช้เป้าหมาย ES5 ก็หมดเหตุผลในการมีอยู่
เลิกใช้ --moduleResolution node (node10)
- สะท้อนอัลกอริทึมการ resolve โมดูลของ Node.js 10 ซึ่งไม่ตรงกับพฤติกรรมของ Node.js รุ่นใหม่
- แนะนำให้ย้ายไปใช้
nodenext(เจาะจง Node.js โดยตรง) หรือbundler(ใช้ bundler/Bun)
เลิกใช้ค่าโมดูล AMD, UMD, SystemJS
--module amd,--module umd,--module systemjs,--module noneไม่ได้รับการรองรับอีกต่อไป- เมื่อ ESM รองรับอย่างแพร่หลายในเบราว์เซอร์และ Node.js แล้ว จึงควรเปลี่ยนไปใช้ bundler หรือกำหนดเป้าหมาย ESM
เลิกใช้ --baseUrl
- เดิมมักใช้เป็นคำนำหน้าของ
pathsแต่ก็ยังทำหน้าที่เป็น lookup root ของการ resolve โมดูลด้วย จึงก่อปัญหาการ resolve path ที่ไม่ตั้งใจ - แนวทางย้ายคือเอา
baseUrlออก แล้วเพิ่มคำนำหน้าโดยตรงในรายการpaths- ตัวอย่าง:
"@app/*": ["app/*"]→"@app/*": ["./src/app/*"]
- ตัวอย่าง:
เลิกใช้ --moduleResolution classic
- เป็นอัลกอริทึมการ resolve โมดูลดั้งเดิมของ TypeScript ซึ่งตอนนี้ทุกกรณีใช้งานที่มีความเป็นจริงสามารถแทนที่ด้วย
nodenextหรือbundlerได้
เลิกใช้ esModuleInterop false และ allowSyntheticDefaultImports false
- ไม่สามารถตั้งสองตัวเลือกนี้เป็น
falseได้อีก ทำให้ พฤติกรรม interop ที่ปลอดภัยเปิดใช้งานเสมอ - อาจต้องปรับจาก
import * as express from "express"เป็นimport express from "express"
เลิกใช้ --alwaysStrict false
- โค้ดทั้งหมดจะถูกมองว่าอยู่ใน JavaScript strict mode ดังนั้นโค้ดที่ใช้
await,static,privateเป็นต้นเป็น identifier ทั่วไป จะต้องเปลี่ยนชื่อ
เลิกใช้ outFile
- เดิมเป็นฟีเจอร์รวมหลายไฟล์ input ให้เป็นไฟล์เดียว แต่ปัจจุบันมี bundler ภายนอก อย่าง Webpack, Rollup, esbuild, Vite มาทดแทนแล้ว
- เป็นการตัดสินใจเพื่อให้ TypeScript โฟกัสกับหน้าที่หลักคือ type checking และ declaration emit
เลิกใช้ไวยากรณ์ module แบบเก่า (การประกาศ namespace)
- ไวยากรณ์
module Foo { ... }ถูก เลิกใช้แบบเด็ดขาด และต้องใช้namespace Foo { ... }แทน - การประกาศ ambient module ในรูป
declare module "some-module" { ... }ยังรองรับเช่นเดิม - มีจุดประสงค์เพื่อหลีกเลี่ยงการชนกับข้อเสนอ
moduleblock ของ ECMAScript
เลิกใช้คีย์เวิร์ด Import asserts
- ต้องเปลี่ยนจาก
import ... asserts { type: "json" }เป็นimport ... with { type: "json" } - เป็นผลจากการที่ข้อเสนอ import assertions เปลี่ยนเป็นข้อเสนอ import attributes (
with)
เลิกใช้ directive no-default-lib
/// <reference no-default-lib="true"/>ไม่รองรับอีกต่อไป และแนะนำให้ใช้--noLibหรือ--libReplacement
ระบุไฟล์ผ่าน command line เมื่อมี tsconfig.json แล้วจะเกิดข้อผิดพลาด
- หากรัน
tsc foo.tsแล้วมีtsconfig.jsonอยู่ในไดเรกทอรีเดียวกัน จะ เกิดข้อผิดพลาด - สามารถละเว้นอย่างชัดเจนได้ด้วยแฟล็ก
--ignoreConfig
การเตรียมพร้อมสำหรับ TypeScript 7.0
- ตัวเลือกที่ถูกเลิกใช้ใน 6.0 ยังใช้งานต่อได้โดยไม่เกิดข้อผิดพลาดผ่านการตั้งค่า
"ignoreDeprecations": "6.0"แต่ จะถูกลบออกทั้งหมดใน 7.0 - สามารถใช้ เครื่องมือ ts5to6 เพื่อปรับค่าอย่าง
baseUrl,rootDirแบบอัตโนมัติได้ - TypeScript 7.0 มีกำหนดออกภายในไม่กี่เดือน และกำลังถูกนำไปใช้แล้วอย่างกว้างขวางในโค้ดเบสขนาดใหญ่ทั้งภายในและภายนอก Microsoft
- แนะนำให้ส่ง feedback ผ่าน native preview nightly build และ ส่วนขยาย VS Code
3 ความคิดเห็น
ตั้งตารอช่วงเวลาที่จะเปลี่ยนผ่านไปสู่คอมไพเลอร์ที่พัฒนาด้วย Go อย่างสมบูรณ์!
หืม? ต่อไป TypeScript จะเปลี่ยนเป็นเนทีฟที่พัฒนาด้วย Go เหรอ?
เฉพาะคอมไพเลอร์เท่านั้น