TypeScript 5.3

匯入屬性 (Import Attributes)

TypeScript 5.3 支援匯入屬性提案的最新更新。

匯入屬性的一個用例是向執行時提供有關模組預期格式的資訊。

ts
// We only want this to be interpreted as JSON,
// not a runnable/malicious JavaScript file with a `.json` extension.
import obj from "./something.json" with { type: "json" };

TypeScript 不會檢查這些屬性的內容,因為它們是宿主特定的。它們會被保留原樣,以便瀏覽器和執行時可以處理它們(並可能報錯)。

ts
// TypeScript is fine with this.
// But your browser? Probably not.
import * as foo from "./foo.js" with { type: "fluffy bunny" };

動態 import() 呼叫也可以透過第二個引數使用匯入屬性。

ts
const obj = await import("./something.json", {
with: { type: "json" }
});

該第二個引數的預期型別由名為 ImportCallOptions 的型別定義,預設情況下它只期望一個名為 with 的屬性。

請注意,匯入屬性是早期提案“匯入斷言”(在 TypeScript 4.5 中實現)的演變。最明顯的區別是使用 with 關鍵字代替了 assert 關鍵字。但不太明顯的區別在於,執行時現在可以自由使用屬性來指導匯入路徑的解析和解釋,而匯入斷言只能在載入模組後斷言某些特徵。

隨著時間的推移,TypeScript 將棄用舊的匯入斷言語法,轉而採用提議的匯入屬性語法。使用 assert 的現有程式碼應遷移到 with 關鍵字。需要匯入屬性的新程式碼應僅使用 with

我們要感謝 Oleksandr Tarasiuk 實現了此提案!同時也感謝 王文路(Wenlu Wang) 實現的匯入斷言

在匯入型別中穩定支援 resolution-mode

在 TypeScript 4.7 中,TypeScript 在 /// <reference types="..." /> 中增加了對 resolution-mode 屬性的支援,以控制識別符號應透過 import 還是 require 語義進行解析。

ts
/// <reference types="pkg" resolution-mode="require" />
// or
/// <reference types="pkg" resolution-mode="import" />

相應的欄位也被新增到僅型別匯入的匯入斷言中;然而,它僅在 TypeScript 的夜間構建版本中受支援。其基本原理是,從本質上講,匯入斷言並不打算用於指導模組解析。因此,該功能以實驗性的方式在夜間模式中釋出,以獲取更多反饋。

但考慮到匯入屬性可以指導解析,且我們已經看到了合理的用例,TypeScript 5.3 現在支援在 import type 中使用 resolution-mode 屬性。

ts
// Resolve `pkg` as if we were importing with a `require()`
import type { TypeFromRequire } from "pkg" with {
"resolution-mode": "require"
};
// Resolve `pkg` as if we were importing with an `import`
import type { TypeFromImport } from "pkg" with {
"resolution-mode": "import"
};
export interface MergedType extends TypeFromRequire, TypeFromImport {}

這些匯入屬性也可以用於 import() 型別。

ts
export type TypeFromRequire =
import("pkg", { with: { "resolution-mode": "require" } }).TypeFromRequire;
export type TypeFromImport =
import("pkg", { with: { "resolution-mode": "import" } }).TypeFromImport;
export interface MergedType extends TypeFromRequire, TypeFromImport {}

更多資訊,請檢視此處的更改

在所有模組模式下支援 resolution-mode

以前,使用 resolution-mode 僅允許在 moduleResolution 選項為 node16nodenext 時使用。為了更容易地專門為型別目的查詢模組,resolution-mode 現在可以在所有其他 moduleResolution 選項(如 bundlernode10)中正常工作,並且在 classic 下也不會報錯。

更多資訊,請參見實現此功能的拉取請求

switch (true) 型別收窄

TypeScript 5.3 現在可以根據 switch (true) 中每個 case 子句裡的條件進行型別收窄。

ts
function f(x: unknown) {
switch (true) {
case typeof x === "string":
// 'x' is a 'string' here
console.log(x.toUpperCase());
// falls through...
case Array.isArray(x):
// 'x' is a 'string | any[]' here.
console.log(x.length);
// falls through...
default:
// 'x' is 'unknown' here.
// ...
}
}

此功能是由 Mateusz Burzyński 發起的初步工作。我們要為這一貢獻表示“感謝!”。

針對布林值的比較進行型別收窄

偶爾你會發現在條件中執行與 truefalse 的直接比較。通常這些是不必要的比較,但出於風格考慮或為了避免圍繞 JavaScript 真值(truthiness)的某些問題,你可能會偏好這樣做。無論如何,以前 TypeScript 在進行收窄時並沒有識別這些形式。

TypeScript 5.3 現在可以跟進並理解這些表示式,從而實現變數的收窄。

ts
interface A {
a: string;
}
interface B {
b: string;
}
type MyType = A | B;
function isA(x: MyType): x is A {
return "a" in x;
}
function someFn(x: MyType) {
if (isA(x) === true) {
console.log(x.a); // works!
}
}

我們要感謝 Mateusz Burzyński 提交了實現此功能的拉取請求

透過 Symbol.hasInstance 進行 instanceof 收窄

JavaScript 中一個稍微晦澀的功能是,可以重寫 instanceof 運算子的行為。為此,instanceof 運算子右側的值需要具有一個由 Symbol.hasInstance 命名的特定方法。

js
class Weirdo {
static [Symbol.hasInstance](testedValue) {
// wait, what?
return testedValue === undefined;
}
}
// false
console.log(new Thing() instanceof Weirdo);
// true
console.log(undefined instanceof Weirdo);

為了更好地模擬 instanceof 中的這種行為,TypeScript 現在會檢查是否存在這樣的 [Symbol.hasInstance] 方法,並將其宣告為型別謂詞函式。如果存在,instanceof 運算子左側被測試的值將透過該型別謂詞進行適當的收窄。

ts
interface PointLike {
x: number;
y: number;
}
class Point implements PointLike {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
distanceFromOrigin() {
return Math.sqrt(this.x ** 2 + this.y ** 2);
}
static [Symbol.hasInstance](val: unknown): val is PointLike {
return !!val && typeof val === "object" &&
"x" in val && "y" in val &&
typeof val.x === "number" &&
typeof val.y === "number";
}
}
function f(value: unknown) {
if (value instanceof Point) {
// Can access both of these - correct!
value.x;
value.y;
// Can't access this - we have a 'PointLike',
// but we don't *actually* have a 'Point'.
value.distanceFromOrigin();
}
}

正如你在本例中看到的,Point 定義了它自己的 [Symbol.hasInstance] 方法。它實際上充當了針對名為 PointLike 的獨立型別的自定義型別保護。在函式 f 中,我們可以使用 instanceofvalue 收窄為 PointLike,但不能Point。這意味著我們可以訪問屬性 xy,但不能訪問方法 distanceFromOrigin

更多資訊,你可以在此處閱讀關於此項更改的內容

對例項欄位上的 super 屬性訪問進行檢查

在 JavaScript 中,可以透過 super 關鍵字訪問基類中的宣告。

js
class Base {
someMethod() {
console.log("Base method called!");
}
}
class Derived extends Base {
someMethod() {
console.log("Derived method called!");
super.someMethod();
}
}
new Derived().someMethod();
// Prints:
// Derived method called!
// Base method called!

這與編寫 this.someMethod() 不同,因為後者可能會呼叫被重寫的方法。這是一個微妙的區別,而當一個宣告從未被重寫時,兩者通常可以互換,這使得該區別變得更加微妙。

js
class Base {
someMethod() {
console.log("someMethod called!");
}
}
class Derived extends Base {
someOtherMethod() {
// These act identically.
this.someMethod();
super.someMethod();
}
}
new Derived().someOtherMethod();
// Prints:
// someMethod called!
// someMethod called!

問題在於,互換使用它們時,super 僅適用於在原型上宣告的成員 — 而非例項屬性。這意味著如果你編寫了 super.someMethod(),但 someMethod 是作為欄位定義的,你將會得到一個執行時錯誤!

ts
class Base {
someMethod = () => {
console.log("someMethod called!");
}
}
class Derived extends Base {
someOtherMethod() {
super.someMethod();
}
}
new Derived().someOtherMethod();
// 💥
// Doesn't work because 'super.someMethod' is 'undefined'.

TypeScript 5.3 現在更仔細地檢查 super 屬性訪問/方法呼叫,以檢視它們是否對應於類欄位。如果對應,我們現在將收到型別檢查錯誤。

此項檢查的貢獻者是 Jack Works

互動式型別內嵌提示 (Inlay Hints)

TypeScript 的內嵌提示現在支援跳轉到型別的定義!這使得在程式碼中導航更加輕鬆。

Ctrl-clicking an inlay hint to jump to the definition of a parameter type.

詳見此處的實現

偏好 type 自動匯入的設定

以前,當 TypeScript 為型別位置的內容生成自動匯入時,它會根據你的設定新增 type 修飾符。例如,在以下程式碼中為 Person 獲取自動匯入時:

ts
export let p: Person

TypeScript 的編輯體驗通常會新增如下匯入:

ts
import { Person } from "./types";
export let p: Person

在某些設定(如 verbatimModuleSyntax)下,它會新增 type 修飾符:

ts
import { type Person } from "./types";
export let p: Person

然而,也許你的程式碼庫無法使用其中一些選項;或者你只是偏好在可能的情況下使用顯式的 type 匯入。

透過近期的更改,TypeScript 現在允許將其作為編輯器特定的選項。在 Visual Studio Code 中,你可以在 UI 中的“TypeScript › Preferences: Prefer Type Only Auto Imports”下啟用它,或者作為 JSON 配置選項 typescript.preferences.preferTypeOnlyAutoImports

透過跳過 JSDoc 解析進行最佳化

當透過 tsc 執行 TypeScript 時,編譯器現在將避免解析 JSDoc。這不僅縮短了解析時間,還減少了儲存註釋所需的記憶體使用量以及垃圾回收所花費的時間。總之,你應該會看到稍微更快的編譯速度和在 --watch 模式下更迅速的反饋。

具體更改可在此處檢視。.

由於並非每個使用 TypeScript 的工具都需要儲存 JSDoc(例如 typescript-eslint 和 Prettier),此解析策略已作為 API 本身的一部分提供。這使得這些工具能夠獲得我們帶給 TypeScript 編譯器的相同記憶體和速度提升。新的註釋解析策略選項在 JSDocParsingMode 中有描述。更多資訊可在此拉取請求中找到。

透過比較非規範化交集進行最佳化

在 TypeScript 中,聯合和交集始終遵循特定形式,即交集不能包含聯合型別。這意味著當我們為像 A & (B | C) 這樣的聯合建立交集時,該交集會被規範化為 (A & B) | (A & C)。不過,在某些情況下,型別系統會為了顯示目的而保留原始形式。

事實證明,原始形式可以用於型別之間一些巧妙的快速路徑比較。

例如,假設我們有 SomeType & (Type1 | Type2 | ... | Type99999NINE),並且我們想看看它是否可賦值給 SomeType。回想一下,我們的源型別其實不是一個交集 — 它是一個看起來像 (SomeType & Type1) | (SomeType & Type2) | ... |(SomeType & Type99999NINE) 的聯合。當檢查聯合是否可賦值給某個目標型別時,我們必須檢查聯合的每個成員是否都可賦值給該目標型別,這可能非常緩慢。

在 TypeScript 5.3 中,我們查看了能夠保留下來的原始交集形式。當我們比較型別時,我們會進行快速檢查,看看目標是否存在於源交集的任何組成部分中。

更多資訊,請參見此拉取請求

tsserverlibrary.jstypescript.js 的合併

TypeScript 本身釋出了兩個庫檔案:tsserverlibrary.jstypescript.js。某些 API 僅在 tsserverlibrary.js 中可用(如 ProjectService API),這對某些匯入者可能有用。然而,這兩者是不同的包且有大量重疊,導致包中程式碼重複。更重要的是,由於自動匯入或習慣記憶,很難始終如一地使用其中一個。不小心載入兩個模組太容易了,而且程式碼可能無法在 API 的另一個例項上正常工作。即使能工作,載入第二個包也會增加資源使用量。

鑑於此,我們決定將兩者合併。typescript.js 現在包含了以前 tsserverlibrary.js 包含的內容,而 tsserverlibrary.js 現在只是簡單地重新匯出 typescript.js。比較此次合併前後的結果,我們看到了包大小的縮減如下:

之前 之後 差異 差異(百分比)
已打包 6.90 MiB 5.48 MiB -1.42 MiB -20.61%
未打包 38.74 MiB 30.41 MiB -8.33 MiB -21.50%
之前 之後 差異 差異(百分比)
lib/tsserverlibrary.d.ts 570.95 KiB 865.00 B -570.10 KiB -99.85%
lib/tsserverlibrary.js 8.57 MiB 1012.00 B -8.57 MiB -99.99%
lib/typescript.d.ts 396.27 KiB 570.95 KiB +174.68 KiB +44.08%
lib/typescript.js 7.95 MiB 8.57 MiB +637.53 KiB +7.84%

換句話說,這使得包大小減少了超過 20.5%。

更多資訊,你可以檢視此項工作的相關內容

破壞性變更和正確性改進

lib.d.ts 變更

為 DOM 生成的型別可能會對你的程式碼庫產生影響。更多資訊,請檢視 TypeScript 5.3 的 DOM 更新

對例項屬性上的 super 訪問進行檢查

TypeScript 5.3 現在可以檢測到 super. 屬性訪問所引用的宣告是否為類欄位,併發出錯誤提示。這可以防止執行時可能發生的錯誤。

在此處檢視關於此更改的更多資訊。.

TypeScript 文件是一個開源專案。請透過傳送 Pull Request 幫助我們改進這些頁面

此頁面的貢獻者
ABAndrew Branch (6)
ELEliran Levi (1)

最後更新:2026 年 3 月 27 日