TypeScript 5.0 中的新功能:聲明符、常量類型、枚舉改進、速度等等!
已發表: 2023-04-15TypeScript 5.0 於 2023 年 3 月 16 日正式發布,現已開放給大家使用。 此版本引入了許多新功能,旨在使 TypeScript 更小、更簡單、更快。
這個新版本對類定制的裝飾器進行了現代化改造,允許以可重用的方式定制類及其成員。 開發人員現在可以將 const 修飾符添加到類型參數聲明中,從而允許類似 const 的推理成為默認值。 新版本還使所有枚舉聯合枚舉,簡化代碼結構並加快 TypeScript 體驗。
在本文中,您將探索 TypeScript 5.0 中引入的變化,深入了解其新特性和功能。
TypeScript 5.0 入門
TypeScript 是一個官方編譯器,您可以使用 npm 安裝到您的項目中。 如果你想在你的項目中開始使用 TypeScript 5.0,你可以在你的項目目錄中運行以下命令:
npm install -D typescript
這會將編譯器安裝在node_modules目錄中,您現在可以使用npx tsc
命令運行該目錄。
您還可以在本文檔中找到有關在 Visual Studio Code 中使用較新版本的 TypeScript 的說明。
TypeScript 5.0 有什麼新功能?
在本文中,讓我們探索 TypeScript 中引入的 5 個主要更新。 這些功能包括:
現代化的裝飾器
裝飾器已經在 TypeScript 中以實驗性標誌出現了一段時間,但新版本使它們跟上了 ECMAScript 提案的步伐,該提案現在處於第 3 階段,這意味著它正處於添加到 TypeScript 的階段。
裝飾器是一種以可重用的方式自定義類及其成員的行為的方法。 例如,如果您的類有兩個方法, greet
和getAge
:
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name}.`); } getAge() { console.log(`I am ${this.age} years old.`); } } const p = new Person('Ron', 30); p.greet(); p.getAge();
在現實世界的用例中,此類應該有更複雜的方法來處理一些異步邏輯並有副作用等,你會想在其中加入一些console.log
調用來幫助調試這些方法。
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log('LOG: Method Execution Starts.'); console.log(`Hello, my name is ${this.name}.`); console.log('LOG: Method Execution Ends.'); } getAge() { console.log('LOG: Method Execution Starts.'); console.log(`I am ${this.age} years old.`); console.log('Method Execution Ends.'); } } const p = new Person('Ron', 30); p.greet(); p.getAge();
這是一個經常出現的模式,如果有一個解決方案可以應用於每個方法會很方便。
這就是裝飾器發揮作用的地方。 我們可以定義一個名為debugMethod
的函數,如下所示:
function debugMethod(originalMethod: any, context: any) { function replacementMethod(this: any, ...args: any[]) { console.log('Method Execution Starts.'); const result = originalMethod.call(this, ...args); console.log('Method Execution Ends.'); return result; } return replacementMethod; }
在上面的代碼中, debugMethod
採用原始方法 ( originalMethod
) 並返回執行以下操作的函數:
- 記錄消息“方法執行開始”。
- 傳遞原始方法及其所有參數(包括 this)。
- 記錄消息“方法執行結束”。
- 返回原始方法返回的任何內容。
通過使用裝飾器,您可以將debugMethod
應用於您的方法,如下面的代碼所示:
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } @debugMethod greet() { console.log(`Hello, my name is ${this.name}.`); } @debugMethod getAge() { console.log(`I am ${this.age} years old.`); } } const p = new Person('Ron', 30); p.greet(); p.getAge();
這將輸出以下內容:
LOG: Entering method. Hello, my name is Ron. LOG: Exiting method. LOG: Entering method. I am 30 years old. LOG: Exiting method.
在定義裝飾器函數 ( debugMethod
) 時,會傳遞第二個參數,稱為context
(它是上下文對象——有一些關於如何聲明裝飾方法以及方法名稱的有用信息)。 您可以更新debugMethod
以從context
對像中獲取方法名稱:
function debugMethod( originalMethod: any, context: ClassMethodDecoratorContext ) { const methodName = String(context.name); function replacementMethod(this: any, ...args: any[]) { console.log(`'${methodName}' Execution Starts.`); const result = originalMethod.call(this, ...args); console.log(`'${methodName}' Execution Ends.`); return result; } return replacementMethod; }
當您運行您的代碼時,輸出現在將包含使用debugMethod
裝飾器裝飾的每個方法的名稱:
'greet' Execution Starts. Hello, my name is Ron. 'greet' Execution Ends. 'getAge' Execution Starts. I am 30 years old. 'getAge' Execution Ends.
您可以使用裝飾器做更多的事情。 請隨時查看原始拉取請求,了解有關如何在 TypeScript 中使用裝飾器的更多信息。
引入 const 類型參數
這是另一個重要版本,它為您提供了一個帶有泛型的新工具,以改進您在調用函數時獲得的推斷。 默認情況下,當您使用const
聲明值時,TypeScript 會推斷類型而不是其文字值:
// Inferred type: string[] const names = ['John', 'Jake', 'Jack'];
到目前為止,要實現所需的推理,您必須通過添加“as const”來使用 const 斷言:
// Inferred type: readonly ["John", "Jake", "Jack"] const names = ['John', 'Jake', 'Jack'] as const;
當你調用函數時,它是相似的。 在下面的代碼中,國家的推斷類型是string[]
:
type HasCountries = { countries: readonly string[] }; function getCountriesExactly(arg: T): T['countries'] { return arg.countries; } // Inferred type: string[] const countries = getCountriesExactly({ countries: ['USA', 'Canada', 'India'] });
您可能需要一種更具體的類型,之前修復的一種方法是添加as const
斷言:

// Inferred type: readonly ["USA", "Canada", "India"] const names = getNamesExactly({ countries: ['USA', 'Canada', 'India'] } as const);
這可能很難記住和實施。 但是,TypeScript 5.0 引入了一項新功能,您可以在其中將 const 修飾符添加到類型參數聲明中,這將默認自動應用類似 const 的推斷。
type HasCountries = { countries: readonly string[] }; function getNamesExactly(arg: T): T['countries'] { return arg.countries; } // Inferred type: readonly ["USA", "Canada", "India"] const names = getNamesExactly({ countries: ['USA', 'Canada', 'India'] });
使用const
類型參數可以讓開發人員在代碼中更清楚地表達意圖。 如果一個變量是常量並且永遠不會改變,那麼使用const
類型參數可以確保它永遠不會被意外改變。
您可以查看原始拉取請求,了解有關 const 類型參數如何在 TypeScript 中工作的更多信息。
枚舉的改進
TypeScript 中的枚舉是一種強大的結構,允許開發人員定義一組命名常量。 在 TypeScript 5.0 中,對枚舉進行了改進,使其更加靈活和有用。
例如,如果您將以下枚舉傳遞給函數:
enum Color { Red, Green, Blue, } function getColorName(colorLevel: Color) { return colorLevel; } console.log(getColorName(1));
在引入 TypeScript 5.0 之前,您可以傳遞錯誤的級別編號,但不會拋出任何錯誤。 但是隨著 TypeScript 5.0 的引入,它會立即拋出錯誤。
此外,新版本通過為每個計算成員創建唯一類型,使所有枚舉成為聯合枚舉。 此增強允許縮小所有枚舉並將其成員引用為類型:
enum Color { Red, Purple, Orange, Green, Blue, Black, White, } type PrimaryColor = Color.Red | Color.Green | Color.Blue; function isPrimaryColor(c: Color): c is PrimaryColor { return c === Color.Red || c === Color.Green || c === Color.Blue; } console.log(isPrimaryColor(Color.White)); // Outputs: false console.log(isPrimaryColor(Color.Red)); // Outputs: true
TypeScript 5.0 的性能改進
TypeScript 5.0 在代碼結構、數據結構和算法擴展方面進行了大量重大更改。 這有助於改善從安裝到執行的整個 TypeScript 體驗,使其更快、更高效。
例如,TypeScript 5.0 和 4.9 的包大小之間的差異是相當可觀的。
TypeScript 最近從命名空間遷移到模塊,允許它利用現代構建工具來執行範圍提升等優化。 此外,刪除一些已棄用的代碼已將 TypeScript 4.9 的 63.8 MB 包大小減少了約 26.4 MB。

以下是 TypeScript 5.0 和 4.9 在速度和大小方面的一些更有趣的勝利:
設想 | 時間或大小相對於 TS 4.9 |
material-ui 構建時間 | 90% |
TypeScript 編譯器啟動時間 | 89% |
編劇建造時間 | 88% |
TypeScript Compiler 自建時間 | 87% |
Outlook Web 構建時間 | 82% |
VS 代碼構建時間 | 80% |
打字稿 npm 包大小 | 59% |
Bundler Resolution 以獲得更好的模塊解析
當您在 TypeScript 中編寫 import 語句時,編譯器需要知道 import 指的是什麼。 它使用模塊解析來做到這一點。 例如,當您編寫import { a } from "moduleA"
時,編譯器需要知道a
在moduleA
中的定義以檢查其使用。
在 TypeScript 4.7 中,為--module
和moduleResolution
設置添加了兩個新選項: node16
和nodenext
。
這些選項的目的是更準確地表示 Node.js 中 ECMAScript 模塊的確切查找規則。 但是,此模式有一些其他工具未強制執行的限制。
例如,在 Node.js 的 ECMAScript 模塊中,任何相對導入都必須包含文件擴展名才能正常工作:
import * as utils from "./utils"; // Wrong import * as utils from "./utils.mjs"; // Correct
TypeScript 引入了一種名為“moduleResolution bundler”的新策略。 可以通過在 TypeScript 配置文件的“compilerOptions”部分添加以下代碼來實現此策略:
{ "compilerOptions": { "target": "esnext", "moduleResolution": "bundler" } }
這種新策略適用於那些使用現代打包器的人,例如 Vite、esbuild、swc、Webpack、Parcel 和其他使用混合查找策略的打包器。
您可以查看原始拉取請求及其實現,以了解moduleResolution
捆綁器如何在 TypeScript 中工作的更多信息。
棄用
TypeScript 5.0 有一些貶值,包括運行時要求、lib.d.ts 更改和 API 重大更改。
- 運行時要求: TypeScript 現在以 ECMAScript 2018 為目標,該包將最低引擎期望設置為 12.20。 因此,Node.js 用戶的最低版本應為 12.20 或更高版本才能使用 TypeScript 5.0。
- lib.d.ts 變化: DOM 類型的生成方式發生了一些變化,這可能會影響現有代碼。 特別是,某些屬性已從數字轉換為數字文字類型,並且用於剪切、複製和粘貼事件處理的屬性和方法已跨接口移動。
- API 重大更改:刪除了一些不必要的接口,並進行了一些正確性改進。 TypeScript 5.0 也轉移到了模塊中。
TypeScript 5.0 棄用了某些設置及其相應的值,包括target: ES3
、 out
、 noImplicitUseStrict
、 keyofStringsOnly
、 suppressExcessPropertyErrors
、 suppressImplicitAnyIndexErrors
、 noStrictGenericChecks
、 charset
、 importsNotUsedAsValues
和preserveValueImports
,以及項目引用中的前綴。
雖然這些配置在 TypeScript 5.5 之前仍然有效,但會發出警告以提醒仍在使用它們的用戶。
概括
在本文中,您了解了 TypeScript 5.0 帶來的一些主要功能和改進,例如對枚舉、捆綁器解析和 const 類型參數的改進,以及對速度和大小的改進。
如果您正在考慮為您的下一個項目使用 TypeScript,請免費試用 Kinsta 的應用程序託管。
現在輪到你了! 您覺得 TypeScript 5.0 中哪些功能或改進最吸引人? 有沒有我們可能忽略的重要內容? 讓我們在評論中知道。