Công bố TypeScript 6.0
(devblogs.microsoft.com)- Đây là bản phát hành cuối cùng dựa trên codebase JavaScript hiện tại, đồng thời là bản phát hành cầu nối để chuẩn bị cho quá trình chuyển sang TypeScript 7.0, bản port native viết bằng Go
- Bao gồm các cải tiến về suy luận kiểu và phân giải mô-đun như nới lỏng tính nhạy ngữ cảnh đối với các hàm không dùng
this, hỗ trợ subpath imports bắt đầu bằng#/ - Hiện đại hóa mạnh mẽ các giá trị mặc định của tùy chọn trình biên dịch như chuyển mặc định
strictsangtrue, mặc địnhtargetthànhes2025, mặc địnhtypesthành[] - Ngừng hỗ trợ hàng loạt tùy chọn legacy như target ES5, mô-đun AMD/UMD/SystemJS,
--baseUrl,--moduleResolution node10 - Bổ sung hỗ trợ kiểu cho các đề xuất ECMAScript Stage 4 mới nhất như Temporal API,
getOrInsert/getOrInsertComputedcủa Map,RegExp.escape
Vị trí của TypeScript 6.0
- Đây là bản phát hành cuối cùng dựa trên codebase JavaScript hiện tại, đóng vai trò cầu nối cho quá trình chuyển sang TypeScript 7.0 (bản port native bằng Go)
- TypeScript 7.0 tận dụng mã native và đa luồng với bộ nhớ dùng chung, và hiện đã rất gần trạng thái hoàn thiện
- Phần lớn thay đổi trong 6.0 nhằm đồng bộ và chuẩn bị cho việc tiếp nhận 7.0
- Có thể trải nghiệm sớm TypeScript 7.0 qua tiện ích mở rộng VS Code hoặc gói npm
Các thay đổi sau Beta và RC
- Điều chỉnh kiểm tra kiểu của biểu thức hàm trong các lời gọi generic, đặc biệt là biểu thức JSX generic — giúp bắt được nhiều lỗi hơn trong code hiện có, nhưng một số lời gọi generic có thể sẽ cần truyền đối số kiểu tường minh
- Mở rộng việc ngừng hỗ trợ cú pháp import assertion (
assert) sang cả lời gọiimport() - Cập nhật kiểu DOM — phản ánh các tiêu chuẩn web mới nhất, bao gồm cả điều chỉnh liên quan đến Temporal API
Nới lỏng tính nhạy ngữ cảnh của các hàm không dùng this
- Khi suy luận kiểu, TypeScript phân loại các hàm có tham số không có kiểu tường minh là hàm nhạy ngữ cảnh (contextually sensitive function), và xử lý chúng ở thứ tự ưu tiên thấp hơn trong quá trình suy luận
- Các hàm viết bằng cú pháp method có tham số
thisngầm, nên khác với arrow function, trước đây luôn bị xem là nhạy ngữ cảnh- Điều này khiến suy luận kiểu đôi khi thất bại tùy theo thứ tự method trong object literal
- Trong TypeScript 6.0, các hàm thực sự không sử dụng
thissẽ không còn bị xem là nhạy ngữ cảnh- Các hàm này được ưu tiên cao hơn trong suy luận kiểu, nên có thể suy luận đúng bất kể thứ tự method
- Được triển khai nhờ đóng góp của Mateusz Burzyński
Hỗ trợ Subpath Imports bắt đầu bằng #/
- Tính năng subpath imports của Node.js cho phép định nghĩa bí danh cho các mô-đun nội bộ gói bằng trường
importstrongpackage.json - Trước đây, sau
#bắt buộc phải có ký tự nên không thể dùng đường dẫn bắt đầu bằng#/- Điều này gây nhầm lẫn cho các lập trình viên đã quen với quy ước tiền tố
@/trong bundler
- Điều này gây nhầm lẫn cho các lập trình viên đã quen với quy ước tiền tố
- Gần đây Node.js đã bắt đầu hỗ trợ subpath imports bắt đầu bằng
#/- Cho phép viết ánh xạ ngắn gọn như
"#/*": "./dist/*"
- Cho phép viết ánh xạ ngắn gọn như
- TypeScript 6.0 hỗ trợ điều này với các tùy chọn
--moduleResolution nodenextvàbundler - Được triển khai nhờ đóng góp của magic-akari
Cho phép kết hợp --moduleResolution bundler với --module commonjs
- Trước đây
--moduleResolution bundlerchỉ dùng được với--module esnexthoặc--module preserve - Do
--moduleResolution node(node10) bị ngừng hỗ trợ, tổ hợp mới này là lộ trình nâng cấp phù hợp nhất cho nhiều dự án - Về lâu dài, vẫn khuyến nghị migrate sang
--module preserve+--moduleResolution bundlerhoặc--module nodenext
Cờ --stableTypeOrdering
- Type ID được gán cho các kiểu trong nội bộ TypeScript phụ thuộc vào thứ tự xử lý, và union type được sắp xếp dựa trên đó
- Điều này có thể gây ra hiện tượng khó đoán khi kết quả emit khai báo thay đổi theo thứ tự khai báo
- TypeScript 7.0 sẽ đưa vào kiểm tra kiểu song song, nên để giải quyết vấn đề gán ID không quyết định, nó dùng thuật toán sắp xếp quyết định dựa trên nội dung
- Ví dụ:
100 | 500sẽ luôn được in ra theo cùng một thứ tự
- Ví dụ:
- Khi bật cờ
--stableTypeOrderingtrong 6.0, có thể đồng bộ hành vi sắp xếp kiểu với 7.0 để giảm khác biệt giữa hai codebase- Có thể làm giảm hiệu năng kiểm tra kiểu tới 25%
- Nếu phát sinh lỗi kiểu do khác biệt suy luận, có thể khắc phục bằng cách thêm đối số kiểu tường minh hoặc annotation cho biến
- Đây là cờ chỉ nhằm chẩn đoán migration từ 6.0 lên 7.0, không khuyến nghị dùng lâu dài
Tùy chọn es2025 (target và lib)
- ES2025 không có tính năng ngôn ngữ JavaScript mới, nhưng có bổ sung kiểu cho các API built-in như
RegExp.escape Promise.try, các phương thức củaIterator, các phương thức củaSetvốn nằm trongesnextnay đã được chuyển sanges2025- Được triển khai nhờ đóng góp của Kenta Moriuchi
Hỗ trợ kiểu cho Temporal API
- TypeScript 6.0 đã bao gồm kiểu built-in cho đề xuất Temporal đã đạt Stage 4
- Có thể dùng với
--target esnexthoặc"lib": ["esnext"](hoặcesnext.temporalchi tiết hơn) - Có thể sử dụng an toàn về kiểu với các API như
Temporal.Now.instant().subtract(),.add() - Đã có mặt trong nhiều runtime và với Stage 4, đây là một phần chính thức của ngôn ngữ JavaScript
- Được triển khai nhờ đóng góp của Renegade334
Hỗ trợ kiểu cho các phương thức "upsert" của Map (getOrInsert / getOrInsertComputed)
- Giúp đơn giản hóa mẫu lặp lại thường gặp là kiểm tra key trong Map rồi thiết lập giá trị mặc định nếu chưa có
- Đề xuất "upsert" của ECMAScript đã đạt Stage 4, bổ sung hai phương thức mới cho
MapvàWeakMapgetOrInsert: nếu key chưa có thì chèn giá trị mặc định được chỉ định rồi trả vềgetOrInsertComputed: khi chi phí tạo giá trị mặc định lớn, có thể tính toán trì hoãn qua callback- Callback nhận key làm đối số, nên cũng có thể dùng để tạo giá trị mặc định dựa trên key
- Đã được thêm vào lib
esnext, có thể dùng ngay trong TypeScript 6.0 - Được triển khai nhờ đóng góp của Renegade334
RegExp.escape
- Hàm
RegExp.escapeđể escape các ký tự đặc biệt trong biểu thức chính quy đã đạt Stage 4 - Có trong lib
es2025, nên dùng được trong TypeScript 6.0 - Được triển khai nhờ đóng góp của Kenta Moriuchi
Tích hợp dom.iterable và dom.asynciterable vào lib dom
- Trước đây, để dùng iteration trên
NodeList,HTMLCollection... cần khai báo"lib": ["dom", "dom.iterable"] - Trong TypeScript 6.0, nội dung của
lib.dom.iterable.d.tsvàlib.dom.asynciterable.d.tsđã được tích hợp hoàn toàn vàolib.dom.d.tsdom.iterable,dom.asynciterablevẫn có thể được tham chiếu nhưng là các file rỗng
- Vì tất cả các trình duyệt hiện đại lớn đều đã hỗ trợ các tính năng này, đây là cải tiến tiện dụng nhằm loại bỏ một điểm dễ gây nhầm lẫn phổ biến
Các thay đổi lớn về giá trị mặc định
strictmặc định làtrue: vì đa số dự án mới đều muốn bật strict mode, các dự án trước đây dựa vào mặc địnhfalsesẽ cần đặt rõ"strict": falsemodulemặc định làesnext: phản ánh thực tế ESM đã trở thành định dạng mô-đun chủ đạotargetmặc định là phiên bản ES mới nhất (hiện làes2025): do runtime evergreen đã phổ biến, không còn cần transpile xuống phiên bản cũnoUncheckedSideEffectImportsmặc định làtrue: giúp phát hiện lỗi gõ sai trong các import chỉ nhằm side effectlibReplacementmặc định làfalse: cải thiện hiệu năng mặc định bằng cách tránh lỗi phân giải mô-đun không cần thiết và giảm số mục bị theo dõi
rootDir đổi mặc định thành .
- Trước đây, nếu không chỉ định thì giá trị này được xác định bằng cách suy luận thư mục chung của mọi file input không phải khai báo
- Điều đó gây ra vấn đề là muốn biết một file có thuộc dự án hay không thì phải load và parse dự án đó
- Trong TypeScript 6.0, mặc định được cố định là thư mục chứa
tsconfig.json - Nếu file nguồn nằm sâu hơn
tsconfig.json, cần chỉ định tường minh như"rootDir": "./src"- Nếu không đặt, có thể sinh ra cấu trúc output ngoài ý muốn như
./dist/src/index.js
- Nếu không đặt, có thể sinh ra cấu trúc output ngoài ý muốn như
types đổi mặc định thành []
- Trước đây, mọi gói trong
node_modules/@typesđều được tự động đưa vào, tạo ra overhead lớn cho thời gian build- Trong các repository thông thường, thường có hàng trăm gói
@typesđược đưa vào gián tiếp
- Trong các repository thông thường, thường có hàng trăm gói
- Trong TypeScript 6.0, mặc định được đổi thành
[](mảng rỗng) để tránh tải các file khai báo không cần thiết - Đã ghi nhận các trường hợp thời gian build cải thiện 20–50%
- Phần lớn dự án sẽ cần cấu hình rõ như
"types": ["node"]hoặc"types": ["node", "jest"]- Có thể khôi phục hành vi cũ bằng
"types": ["*"]
- Có thể khôi phục hành vi cũ bằng
Các mục ngừng hỗ trợ (Deprecation)
target: es5 bị ngừng hỗ trợ
- Target ES5 gần như không còn trường hợp sử dụng vì IE đã bị khai tử và trình duyệt evergreen đã phổ biến
- Target tối thiểu được nâng lên ES2015, nếu cần output ES5 thì nên dùng trình biên dịch bên ngoài
--downlevelIteration bị ngừng hỗ trợ
- Tùy chọn này chỉ có tác dụng với emit ES5, nên mất mục đích khi ES5 bị ngừng hỗ trợ
--moduleResolution node (node10) bị ngừng hỗ trợ
- Phản ánh thuật toán phân giải mô-đun của Node.js 10, không còn khớp với hành vi của Node.js hiện đại
- Khuyến nghị migrate sang
nodenext(target trực tiếp Node.js) hoặcbundler(dùng bundler/Bun)
Các giá trị mô-đun AMD, UMD, SystemJS bị ngừng hỗ trợ
--module amd,--module umd,--module systemjs,--module noneđều không còn được hỗ trợ- Vì ESM đã được hỗ trợ rộng rãi trong cả trình duyệt lẫn Node.js, cần chuyển sang bundler hoặc target ESM
--baseUrl bị ngừng hỗ trợ
- Dù chủ yếu được dùng làm tiền tố cho
paths, nó cũng hoạt động như gốc tra cứu trong phân giải mô-đun, dễ gây ra các vấn đề phân giải đường dẫn ngoài ý muốn - Có thể migrate bằng cách bỏ
baseUrlvà thêm trực tiếp tiền tố vào từng mụcpaths- Ví dụ:
"@app/*": ["app/*"]→"@app/*": ["./src/app/*"]
- Ví dụ:
--moduleResolution classic bị ngừng hỗ trợ
- Đây là thuật toán phân giải mô-đun ban đầu của TypeScript, hiện mọi trường hợp thực tế đều có thể thay bằng
nodenexthoặcbundler
esModuleInterop false và allowSyntheticDefaultImports false bị ngừng hỗ trợ
- Không thể đặt hai tùy chọn này là
falsenữa, nên hành vi interop an toàn luôn được bật - Cần điều chỉnh như
import * as express from "express"→import express from "express"
--alwaysStrict false bị ngừng hỗ trợ
- Mọi mã đều được xem là chạy trong JavaScript strict mode, nên những mã dùng
await,static,private... như định danh thông thường sẽ cần đổi tên
outFile bị ngừng hỗ trợ
- Đây là tính năng gộp nhiều file input thành một, nhưng nay đã được các bundler bên ngoài thay thế như Webpack, Rollup, esbuild, Vite
- Quyết định này nhằm giúp TypeScript tập trung vào vai trò cốt lõi là kiểm tra kiểu và emit khai báo
Cú pháp module legacy (khai báo namespace) bị ngừng hỗ trợ
- Cú pháp
module Foo { ... }bị ngừng hỗ trợ hoàn toàn, cần dùngnamespace Foo { ... } - Khai báo ambient module dạng
declare module "some-module" { ... }vẫn tiếp tục được hỗ trợ - Mục đích là tránh xung đột với đề xuất
moduleblock của ECMAScript
Từ khóa import asserts bị ngừng hỗ trợ
- Cần đổi từ
import ... asserts { type: "json" }sangimport ... with { type: "json" } - Đây là thay đổi theo việc đề xuất import assertions được chuyển thành đề xuất import attributes (
with)
Directive no-default-lib bị ngừng hỗ trợ
/// <reference no-default-lib="true"/>không còn được hỗ trợ, nên dùng--noLibhoặc--libReplacement
Lỗi khi chỉ định file dòng lệnh nếu có tsconfig.json
- Khi chạy
tsc foo.ts, nếu cùng thư mục cótsconfig.jsonthì sẽ phát sinh lỗi - Có thể bỏ qua tường minh bằng cờ
--ignoreConfig
Chuẩn bị cho TypeScript 7.0
- Các tùy chọn bị ngừng hỗ trợ trong 6.0 vẫn có thể tiếp tục dùng không lỗi bằng cấu hình
"ignoreDeprecations": "6.0", nhưng sẽ bị loại bỏ hoàn toàn trong 7.0 - Có thể dùng công cụ ts5to6 để tự động điều chỉnh như
baseUrl,rootDir - TypeScript 7.0 dự kiến phát hành trong vài tháng tới và đã được tiếp nhận rộng rãi trong các codebase lớn cả trong lẫn ngoài Microsoft
- Khuyến khích dùng bản dựng nightly native preview và tiện ích mở rộng VS Code để gửi phản hồi
3 bình luận
Mình rất mong chờ thời điểm chuyển hoàn toàn sang trình biên dịch dựa trên Go!
Hả? Sau này TypeScript sẽ chuyển sang native dựa trên Go à?
Chỉ compiler thôi