TypeScript 內建型別宣告(lib.es2020.d.ts)
簡介
在使用 TypeScript 開發現代 JavaScript 應用時,型別安全是最核心的價值之一。TypeScript 之所以能提供完善的型別檢查,背後依賴一套完整的型別宣告檔(.d.ts),其中最常被使用的就是隨 TypeScript 套件一起提供的 lib.es2020.d.ts。
lib.es2020.d.ts 包含了 ECMAScript 2020(ES2020)規範中所有全域物件、內建函式與新加入的語法(例如 BigInt、Promise.allSettled、globalThis 等)的型別資訊。只要正確引用這份宣告檔,編譯器就能在編寫程式碼時即時偵測錯誤、提供自動完成與文件說明,極大提升開發效率與程式品質。
本篇文章將深入探討 lib.es2020.d.ts 的結構與使用方式,說明常見的型別宣告技巧,並提供實務範例與最佳實踐,幫助你在日常開發中善用這份內建型別庫。
核心概念
1. 為什麼需要 lib.es2020.d.ts?
- 全域型別補完:不需要自行撰寫
Array.prototype.map、Set、Date等的型別,編譯器已經幫你完成。 - 版本對應:不同的 ECMAScript 版本對應不同的
lib,es2020包含了es2015、es2016、es2017、es2018、es2019的所有宣告,且加入了 ES2020 新增的功能。 - 自訂 lib:若專案只需要舊版特性,可在
tsconfig.json的lib欄位指定較舊的版本;若需要最新版特性,只要包含es2020(或更高)即可。
2. lib 欄位的設定
{
"compilerOptions": {
"target": "ES2020",
"lib": ["es2020", "dom"] // 同時加入瀏覽器 DOM 型別
}
}
target決定編譯後的 JavaScript 版本,若設定為ES2020,編譯器會自動把es2020加入lib。lib可自行覆寫,若只寫["es2020"],則不會載入dom(如document、window)的型別。
3. 內建型別的組成
lib.es2020.d.ts 主要由以下幾類型別組成:
| 類別 | 說明 |
|---|---|
| 全域變數 | Infinity、NaN、globalThis |
| 全域函式 | parseInt、parseFloat、isNaN |
| 內建物件 | Array<T>、Map<K,V>、Set<T>、Promise<T> |
| 新語法 | BigInt、Symbol.prototype.description、Promise.allSettled |
| DOM(若載入) | HTMLElement、fetch、AbortController |
小提醒:
lib.es2020.d.ts只提供型別資訊,實際執行環境仍需支援相對應的 JavaScript 功能(例如 Node.js 12+ 才支援BigInt)。
程式碼範例
以下示範 5 個常見且實用的 ES2020 型別使用情境,皆可直接在 TypeScript 中獲得型別提示與錯誤檢查。
範例 1️⃣ BigInt 與數值安全
// 使用 ES2020 的 BigInt 來處理超出 Number 安全範圍的整數
const largeNumber: bigint = 123456789012345678901234567890n;
// 型別錯誤示範:不能把 number 直接指派給 bigint
// const wrong: bigint = 42; // ❌ 編譯錯誤
// 與其他 bigint 進行算術運算
const result = largeNumber * 2n; // result 仍是 bigint
console.log(result.toString()); // "246913578024691357802469135780"
重點:
bigint必須以n後綴或BigInt()建構子產生,且所有運算子也必須是bigint,否則會產生型別錯誤。
範例 2️⃣ Promise.allSettled 的型別推斷
// 多個非同步任務,使用 allSettled 取得每個任務的最終狀態
const promises = [
fetch('https://api.example.com/users').then(r => r.json()),
fetch('https://api.example.com/posts').then(r => r.json()),
Promise.reject(new Error('Network error'))
] as const; // 讓陣列成為 tuple,保留每個元素的具體型別
type SettledResult = Awaited<ReturnType<typeof Promise.allSettled>>;
// allSettled 回傳的型別為 (PromiseFulfilledResult<T> | PromiseRejectedResult)[]
const results = await Promise.allSettled(promises);
results.forEach((res, idx) => {
if (res.status === 'fulfilled') {
console.log(`Promise ${idx} fulfilled:`, res.value);
} else {
console.error(`Promise ${idx} rejected:`, res.reason);
}
});
說明:
Promise.allSettled會返回每個 Promise 的 狀態(fulfilled或rejected),型別宣告在lib.es2020.d.ts中已完整定義,讓開發者不必自行撰寫type。
範例 3️⃣ globalThis 的跨環境存取
// 在 Node、瀏覽器或 WebWorker 中皆可安全取得全域物件
declare const globalThis: typeof globalThis; // 型別已在 lib.es2020.d.ts 中宣告
// 例:在全域掛載自訂屬性
(globalThis as any).myAppVersion = '1.3.0';
// 讀取時會得到正確的型別推斷
const version: string = (globalThis as any).myAppVersion;
console.log('App version:', version);
技巧:若要在 TypeScript 中擴充
globalThis,可使用 模組擴充(declare global)方式,避免any。
範例 4️⃣ String.prototype.replaceAll(ES2021 之前的 polyfill)
雖然 replaceAll 是 ES2021 的功能,但在 es2020 中已提供 型別聲明,可供 polyfill 使用。
// 若執行環境不支援 replaceAll,先自行實作
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function (search, replace) {
// 這裡的 this 會被推斷為 string
return this.split(search).join(replace);
};
}
// 正常使用,編譯器會正確提示型別
const text = 'apple,banana,apple';
const newText = text.replaceAll('apple', 'orange');
console.log(newText); // "orange,banana,orange"
提醒:即使執行環境缺少此功能,只要在程式碼中加入上述 polyfill,型別檢查仍會通過,因為
replaceAll已在lib.es2020.d.ts中宣告。
範例 5️⃣ WeakRef(弱參考)與垃圾回收
// WeakRef 允許持有對象的弱引用,不會阻止垃圾回收
class Cache<T> {
private ref: WeakRef<T>;
constructor(value: T) {
this.ref = new WeakRef(value);
}
get(): T | undefined {
// deref() 會回傳目標物件或 undefined(已被回收)
return this.ref.deref();
}
}
// 使用示例
let obj = { name: 'Temp' };
const cache = new Cache(obj);
console.log(cache.get()?.name); // "Temp"
obj = null; // 解除強參考,可能被 GC 回收
// 下一次呼叫 get() 可能得到 undefined
重點:
WeakRef的型別在es2020中已完整宣告,使用時只要注意deref()可能回傳undefined,即可避免跑時錯誤。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方案 |
|---|---|---|
未正確設定 lib |
tsconfig.json 若只指定 ["es5"],則 es2020 的型別不會被載入,會出現 Property 'replaceAll' does not exist 等錯誤。 |
確認 compilerOptions.lib 包含 "es2020"(或更高)或直接使用 target: "ES2020"。 |
any 逃逸 |
為了快速解決型別錯誤,常會把 globalThis、window 等寫成 any,失去型別安全。 |
使用 型別斷言或 declare global 來擴充型別,而非直接 any。 |
混用 bigint 與 number |
直接把 bigint 與 number 做算術運算會產生編譯錯誤。 |
在需要混合計算時,先使用 Number() 或 BigInt() 轉型,或保持同一型別。 |
Promise.allSettled 回傳類型過寬 |
若未使用 as const,TypeScript 只能推斷為 any[],失去具體型別。 |
使用 tuple (as const) 或自行定義 type,讓每個 Promise 的回傳型別被保留下來。 |
| Polyfill 與型別不匹配 | 手動實作的 polyfill 若未符合宣告檔的簽名,會產生型別衝突。 | 參考 lib.es2020.d.ts 中的介面定義,確保函式參數與回傳型別一致。 |
最佳實踐
- 明確指定
target與lib:在tsconfig.json中以target: "ES2020"為基礎,視需求再加入"dom"、"webworker"等。 - 善用型別斷言與
declare global:若需要擴充全域物件,使用 模組擴充 而非any。 - 保持型別一致性:在處理
bigint、Promise、WeakRef等新特性時,盡量讓整段程式碼保持相同型別,避免混用。 - 利用
as const讓 tuple 保留具體型別:對於多個異質 Promise,使用as const能讓allSettled的結果更精確。 - 定期升級 TypeScript:新版的
lib檔會加入最新 ECMAScript 標準的型別,升級後可直接享受新功能的型別支援。
實際應用場景
1. 大型前端專案的跨瀏覽器支援
在一個使用 React + Vite 的前端專案中,開發團隊決定以 ES2020 為基礎開發,同時需要支援舊版瀏覽器(IE 11 除外)。透過在 tsconfig.json 加入:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["es2020", "dom"],
"downlevelIteration": true
}
}
BigInt用於前端計算金融金額的精確度。Promise.allSettled處理多個 API 並行請求,確保即使部分失敗也不會中斷 UI 更新。globalThis作為跨環境儲存全域設定(例如語系、使用者資訊),避免在 Node 與瀏覽器間寫不同程式碼。
2. Node.js 微服務的型別安全
在一個使用 NestJS 建置的 Node.js 微服務,目標 Node 版本為 14(支援 ES2020)。tsconfig.json 設定:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["es2020"]
}
}
WeakRef用於緩存資料庫查詢結果,避免記憶體泄漏。BigInt處理分布式 ID(Snowflake)時避免 53 位整數上限問題。globalThis用於在測試環境注入模擬的全域變數,保持測試與正式環境程式碼一致。
3. 共享程式庫(Monorepo)中的型別一致性
在一個 Monorepo 中,前端與後端共用 utils 套件。套件內部使用 es2020 的型別宣告,確保:
- 前端使用
replaceAll時不必額外安裝 polyfill。 - 後端使用
Promise.allSettled處理多個 I/O 操作,返回的型別在前端與後端皆保持一致。
透過統一的 tsconfig.base.json,所有子專案皆繼承相同的 lib 設定,避免因版本不一致產生的型別衝突。
總結
lib.es2020.d.ts 是 TypeScript 內建的型別宣告檔,負責把 ES2020 標準的所有全域物件、內建函式與新語法以型別的形式提供給開發者。正確設定 target 與 lib,即可在開發過程中即時獲得 型別安全、智能補完與文件說明,大幅減少執行時錯誤與除錯成本。
本文從 概念說明、實用範例、常見陷阱與最佳實踐,到 實際應用場景,完整展示了如何在前端與後端專案中善用 lib.es2020.d.ts。未來隨著 ECMAScript 標準的演進,只要保持 TypeScript 版本的更新與 lib 設定的同步,就能持續享受最新語法的型別支援,寫出更安全、更可靠的程式碼。
關鍵 takeaway:
- 設定正確的
lib,讓編譯器自動帶入 ES2020 型別。- 避免
any,利用declare global、型別斷言或as const取得精確型別。- 善用新特性(
BigInt、Promise.allSettled、WeakRef、globalThis),提升程式碼的表達力與效能。
祝你在 TypeScript 的型別世界裡,寫程式更得心應手!