本文 AI 產出,尚未審核

TypeScript 內建型別宣告(lib.es2020.d.ts)


簡介

在使用 TypeScript 開發現代 JavaScript 應用時,型別安全是最核心的價值之一。TypeScript 之所以能提供完善的型別檢查,背後依賴一套完整的型別宣告檔(.d.ts),其中最常被使用的就是隨 TypeScript 套件一起提供的 lib.es2020.d.ts

lib.es2020.d.ts 包含了 ECMAScript 2020(ES2020)規範中所有全域物件、內建函式與新加入的語法(例如 BigIntPromise.allSettledglobalThis 等)的型別資訊。只要正確引用這份宣告檔,編譯器就能在編寫程式碼時即時偵測錯誤、提供自動完成與文件說明,極大提升開發效率與程式品質。

本篇文章將深入探討 lib.es2020.d.ts 的結構與使用方式,說明常見的型別宣告技巧,並提供實務範例與最佳實踐,幫助你在日常開發中善用這份內建型別庫。


核心概念

1. 為什麼需要 lib.es2020.d.ts

  • 全域型別補完:不需要自行撰寫 Array.prototype.mapSetDate 等的型別,編譯器已經幫你完成。
  • 版本對應:不同的 ECMAScript 版本對應不同的 libes2020 包含了 es2015es2016es2017es2018es2019 的所有宣告,且加入了 ES2020 新增的功能。
  • 自訂 lib:若專案只需要舊版特性,可在 tsconfig.jsonlib 欄位指定較舊的版本;若需要最新版特性,只要包含 es2020(或更高)即可。

2. lib 欄位的設定

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["es2020", "dom"]   // 同時加入瀏覽器 DOM 型別
  }
}
  • target 決定編譯後的 JavaScript 版本,若設定為 ES2020,編譯器會自動把 es2020 加入 lib
  • lib 可自行覆寫,若只寫 ["es2020"],則不會載入 dom(如 documentwindow)的型別。

3. 內建型別的組成

lib.es2020.d.ts 主要由以下幾類型別組成:

類別 說明
全域變數 InfinityNaNglobalThis
全域函式 parseIntparseFloatisNaN
內建物件 Array<T>Map<K,V>Set<T>Promise<T>
新語法 BigIntSymbol.prototype.descriptionPromise.allSettled
DOM(若載入) HTMLElementfetchAbortController

小提醒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 的 狀態fulfilledrejected),型別宣告在 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 逃逸 為了快速解決型別錯誤,常會把 globalThiswindow 等寫成 any,失去型別安全。 使用 型別斷言declare global 來擴充型別,而非直接 any
混用 bigintnumber 直接把 bigintnumber 做算術運算會產生編譯錯誤。 在需要混合計算時,先使用 Number()BigInt() 轉型,或保持同一型別。
Promise.allSettled 回傳類型過寬 若未使用 as const,TypeScript 只能推斷為 any[],失去具體型別。 使用 tuple (as const) 或自行定義 type,讓每個 Promise 的回傳型別被保留下來。
Polyfill 與型別不匹配 手動實作的 polyfill 若未符合宣告檔的簽名,會產生型別衝突。 參考 lib.es2020.d.ts 中的介面定義,確保函式參數與回傳型別一致。

最佳實踐

  1. 明確指定 targetlib:在 tsconfig.json 中以 target: "ES2020" 為基礎,視需求再加入 "dom""webworker" 等。
  2. 善用型別斷言與 declare global:若需要擴充全域物件,使用 模組擴充 而非 any
  3. 保持型別一致性:在處理 bigintPromiseWeakRef 等新特性時,盡量讓整段程式碼保持相同型別,避免混用。
  4. 利用 as const 讓 tuple 保留具體型別:對於多個異質 Promise,使用 as const 能讓 allSettled 的結果更精確。
  5. 定期升級 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 標準的所有全域物件、內建函式與新語法以型別的形式提供給開發者。正確設定 targetlib,即可在開發過程中即時獲得 型別安全、智能補完與文件說明,大幅減少執行時錯誤與除錯成本。

本文從 概念說明實用範例常見陷阱與最佳實踐,到 實際應用場景,完整展示了如何在前端與後端專案中善用 lib.es2020.d.ts。未來隨著 ECMAScript 標準的演進,只要保持 TypeScript 版本的更新與 lib 設定的同步,就能持續享受最新語法的型別支援,寫出更安全、更可靠的程式碼。

關鍵 takeaway

  • 設定正確的 lib,讓編譯器自動帶入 ES2020 型別。
  • 避免 any,利用 declare global、型別斷言或 as const 取得精確型別。
  • 善用新特性BigIntPromise.allSettledWeakRefglobalThis),提升程式碼的表達力與效能。

祝你在 TypeScript 的型別世界裡,寫程式更得心應手!