this 无关函数的上下文敏感性降低
🌐 Less Context-Sensitivity on this-less Functions
当参数没有明确写出类型时,TypeScript 通常可以根据预期类型推断它们,或者甚至通过同一函数调用中的其他参数推断。
🌐 When parameters don’t have explicit types written out, TypeScript can usually infer them based on an expected type, or even through other arguments in the same function call.
tsdeclare function callIt<T>(obj: {produce: (x: number) => T,consume: (y: T) => void,}): void;// Works, no issues.callIt({produce: (x: number) => x * 2,consume: y => y.toFixed(),});// Works, no issues even though the order of the properties is flipped.callIt({consume: y => y.toFixed(),produce: (x: number) => x * 2,});
在这里,TypeScript 可以根据从 produce 函数推断出的 T 推断 consume 函数中 y 的类型,而不管属性的顺序如何。 但是,如果这些函数是使用方法语法而不是箭头函数语法编写的,会怎样呢?
🌐 Here, TypeScript can infer the type of y in the consume function based on the inferred T from the produce function, regardless of the order of the properties.
But what about if these functions were written using method syntax instead of arrow function syntax?
tsdeclare function callIt<T>(obj: {produce: (x: number) => T,consume: (y: T) => void,}): void;// Works fine, `x` is inferred to be a number.callIt({produce(x: number) { return x * 2; },consume(y) { return y.toFixed(); },});callIt({consume(y) { return y.toFixed(); },// ~// error: 'y' is of type 'unknown'.produce(x: number) { return x * 2; },});
奇怪的是,对 callIt 的第二次调用会导致错误,因为 TypeScript 无法推断 consume 方法中 y 的类型。这里发生的情况是,当 TypeScript 尝试为 T 寻找候选项时,它会先跳过那些参数没有显式类型的函数。之所以这样做,是因为某些函数可能需要 T 的推断类型才能正确检查——在我们的例子中,我们需要知道 T 的类型才能分析我们的 consume 函数。
🌐 Strangely enough, the second call to callIt results in an error because TypeScript is not able to infer the type of y in the consume method.
What’s happening here is that when TypeScript is trying to find candidates for T, it will first skip over functions whose parameters don’t have explicit types.
It does this because certain functions may need the inferred type of T to be correctly checked - in our case, we need to know the type of T to analyze our consume function.
这些函数被称为上下文敏感函数——本质上是具有没有显式类型的参数的函数。最终,类型系统需要为这些参数确定类型——但这与泛型函数中的推断方式有些矛盾,因为两者对类型的“拉动”方向不同。
🌐 These functions are called contextually sensitive functions - basically, functions that have parameters without explicit types. Eventually the type system will need to figure out types for these parameters - but this is a bit at odds with how inference works in generic functions because the two “pull” on types in different directions.
tsfunction callFunc<T>(callback: (x: T) => void, value: T) {return callback(value);}callFunc(x => x.toFixed(), 42);// ^// We need to figure out the type of `x` here,// but we also need to figure out the type of `T` to check the callback.
为了解决这个问题,TypeScript 在类型参数推断时会跳过上下文敏感的函数,而是先检查并从其他参数中推断。
如果跳过上下文敏感的函数无效,推断就会继续跨过任何未检查的参数,从参数列表的左到右进行。
在上面的例子中,TypeScript 在为 T 推断时会跳过回调,但随后会查看第二个参数 42,并推断 T 是 number。
然后,当回过头来检查回调时,它将拥有一个上下文类型 (x: number) => void,这允许它推断 x 也是一个 number。
🌐 To solve this, TypeScript skips over contextually sensitive functions during type argument inference, and instead checks and infers from other arguments first.
If skipping over contextually sensitive functions doesn’t work, inference just continues across any unchecked arguments, going left-to-right in the argument list.
In the example immediately above, TypeScript will skip over the callback during inference for T, but will then look at the second argument, 42, and infer that T is number.
Then, when it comes back to check the callback, it will have a contextual type of (x: number) => void, which allows it to infer that x is a number as well.
那么我们之前的例子中发生了什么?
🌐 So what’s going on in our earlier examples?
ts// Arrow syntax - no errors.callIt({consume: y => y.toFixed(),produce: (x: number) => x * 2,});// Method syntax - errors!callIt({consume(y) { return y.toFixed(); },// ~// error: 'y' is of type 'unknown'.produce(x: number) { return x * 2; },});
在这两个例子中,produce 被分配了一个带有显式类型 x 参数的函数。它们不应该被相同地检查吗?
🌐 In both examples, produce is assigned a function with an explicitly-typed x parameter.
Shouldn’t they be checked identically?
这个问题很微妙:大多数函数(比如使用方法语法的那些)都有一个隐式的 this 参数,但箭头函数没有。任何对 this 的使用都可能需要“拉取” T 的类型——例如,知道包含对象字面量的类型可能进而需要 consume 的类型,而 consume 使用了 T。
🌐 The issue is subtle: most functions (like the ones using method syntax) have an implicit this parameter, but arrow functions do not.
Any usage of this could require “pulling” on the type of T - for example, knowing the type of the containing object literal could in turn require the type of consume, which uses T.
但我们并没有使用 this!当然,该函数在运行时可能会有一个 this 值,但它从未被使用过!
🌐 But we’re not using this!
Sure, the function might have a this value at runtime, but it’s never used!
当 TypeScript 6.0 决定一个函数是否具有上下文敏感性时,会考虑这一点。如果 this 在函数中从未真正使用过,则它不被认为是上下文敏感的。这意味着在类型推断时,这些函数将被视为优先级更高的函数,而且我们上面的所有示例现在都可以正常工作!
🌐 TypeScript 6.0 takes this into account when it decides if a function is contextually sensitive or not.
If this is never actually used in a function, then it is not considered contextually sensitive.
That means these functions will be seen as higher-priority when it comes to type inference, and all of our examples above now work!
[这一更改由Mateusz Burzyński的工作提供](https://github.com/microsoft/TypeScript/pull/62243)。
以 #/ 开头的子路径导入
🌐 Subpath Imports Starting with #/
当 Node.js 添加对模块的支持时,它增加了一个名为“子路径导入”的功能。这基本上是一个名为 imports 的字段,允许包为其包内的模块创建内部别名。
🌐 When Node.js added support for modules, it added a feature called “subpath imports”.
This is basically a field called imports which allows packages to create internal aliases for modules within their package.
json{"name": "my-package","type": "module","imports": {"#root/*": "./dist/*"}}
这允许 my-package 中的模块从以 #root/ 开头的路径导入
🌐 This allows modules in my-package to import from paths starting with #root/
jsimport * as utils from "#root/utils.js";
而不是使用如下的相对路径。
🌐 instead of using a relative path like the following.
jsimport * as utils from "../../utils.js";
这个功能的一个小烦恼是,开发者在指定子路径导入时,总是必须在 # 后面写一些东西。这里,我们使用了 root,但它有点没用,因为我们映射的目录除了 ./dist/ 之外没有其他目录。
🌐 One minor annoyance with this feature has been that developers always had to write something after the # when specifying a subpath import.
Here, we used root, but it is a bit useless since there is no directory we’re mapping over other than ./dist/
使用过打包工具的开发者也习惯使用路径映射来避免冗长的相对路径。
对于打包工具而言,一个熟悉的惯例是使用简单的 @/ 作为前缀。
不幸的是,子路径导入根本不能以 #/ 开头,这导致了很多开发者在尝试在项目中采用它们时感到困惑。
🌐 Developers who have used bundlers are also accustomed to using path-mapping to avoid long relative paths.
A familiar convention with bundlers has been to use a simple @/ as the prefix.
Unfortunately, subpath imports could not start with #/ at all, leading to a lot of confusion for developers trying to adopt them in their projects.
但最近,Node.js 增加了对以 #/ 开头的子路径导入的支持。
这允许包使用一个简单的 #/ 前缀进行子路径导入,而无需添加额外的段。
🌐 But more recently, Node.js added support for subpath imports starting with #/.
This allows packages to use a simple #/ prefix for their subpath imports without needing to add an extra segment.
json{"name": "my-package","type": "module","imports": {"#/*": "./dist/*"}}
这在更新的 Node.js 20 版本中得到支持,因此 TypeScript 现在在 --moduleResolution 设置下通过 nodenext 和 bundler 选项支持它。
🌐 This is supported in newer Node.js 20 releases, and so TypeScript now supports it under the options nodenext and bundler for the --moduleResolution setting.
这项工作得益于 magic-akari,实现的拉取请求可以在这里找到。
🌐 This work was done thanks to magic-akari, and the implementing pull request can be found here.
将 --moduleResolution bundler 与 --module commonjs 结合
🌐 Combining --moduleResolution bundler with --module commonjs
TypeScript 的 --moduleResolution bundler 设置以前只能与 --module esnext 或 --module preserve 一起使用;然而,随着 --moduleResolution node(又名 --moduleResolution node10)的弃用,这种新的组合通常是许多项目最合适的升级路径。
🌐 TypeScript’s --moduleResolution bundler setting was previously only allowed to be used with --module esnext or --module preserve;
however, with the deprecation of --moduleResolution node (a.k.a. --moduleResolution node10), this new combination is often the most suitable upgrade path for many projects.
项目通常会希望改为计划迁移到任一方向
🌐 Projects will often want to instead plan out a migration towards either
--module preserve和--moduleResolution bundler--module nodenext
取决于你的项目类型(例如打包的 Web 应用、Bun 应用或 Node.js 应用)。
🌐 depending on your project type (e.g. bundled web app, Bun app, or Node.js app).
更多信息可以在此实现拉取请求中找到。
🌐 More information can be found at this implementing pull request.
--stableTypeOrdering 标志
🌐 The --stableTypeOrdering Flag
作为我们对 TypeScript 原生移植 持续工作的部分,我们引入了一个新的标志,称为 --stableTypeOrdering,旨在协助从 6.0 到 7.0 的迁移。
🌐 As part of our ongoing work on TypeScript’s native port, we’ve introduced a new flag called --stableTypeOrdering intended to assist with 6.0-to-7.0 migrations.
今天,TypeScript 会按照遇到类型的顺序为类型分配类型ID(内部跟踪编号),并使用这些ID以一致的方式对联合类型进行排序。类似的过程也会发生在属性上。因此,程序中声明事物的顺序可能会对诸如声明输出之类的内容产生可能令人惊讶的影响。
🌐 Today, TypeScript assigns type IDs (internal tracking numbers) to types in the order they are encountered, and uses these IDs to sort union types in a consistent manner. A similar process occurs for properties. As a result, the order in which things are declared in a program can have possibly surprising effects on things like declaration emit.
例如,考虑从此文件发出的声明:
🌐 For example, consider the declaration emit from this file:
ts// Input: some-file.tsexport function foo(condition: boolean) {return condition ? 100 : 500;}// Output: some-file.d.tsexport declare function foo(condition: boolean): 100 | 500;// ^^^^^^^^^// Note the order of this union: 100, then 500.
如果我们在 foo 之上添加一个不相关的 const,声明的生成会有所变化:
🌐 If we add an unrelated const above foo, the declaration emit changes:
ts// Input: some-file.tsconst x = 500;export function foo(condition: boolean) {return condition ? 100 : 500;}// Output: some-file.d.tsexport declare function foo(condition: boolean): 500 | 100;// ^^^^^^^^^// Note the change in order here.
这是因为字面量类型 500 的类型 ID 比 100 低,这是因为在分析 const x 声明时它先被处理了。在极少数情况下,这种顺序的变化甚至可能导致错误根据程序处理顺序的不同而出现或消失,但通常,你可能注意到这种顺序的主要地方是在生成的声明文件中,或是在编辑器中类型的显示方式上。
🌐 This happens because the literal type 500 gets a lower type ID than 100 because it was processed first when analyzing the const x declaration.
In very rare cases this change in ordering can even cause errors to appear or disappear based on program processing order, but in general, the main place you might notice this ordering is in the emitted declaration files, or in the way types are displayed in your editor.
TypeScript 7 的主要架构改进之一是并行类型检查,这大大提高了整体检查时间。然而,并行性引入了一个挑战:当不同的类型检查器以不同的顺序访问节点、类型和符号时,这些构造分配的内部 ID 会变得不可预测。这反过来会导致令人困惑的非确定性输出,其中同一程序中内容相同的两个文件可能生成不同的声明文件,甚至在分析同一文件时计算出不同的错误。为了解决这个问题,TypeScript 7.0 会根据对象内容的确定性算法对其内部对象(例如类型和符号)进行排序。这确保了所有检查器无论创建时间和方式如何,都遇到相同的对象顺序。因此,在给定示例中,TypeScript 7 将始终打印 100 | 500,完全消除了顺序不稳定性。
🌐 One of the major architectural improvements in TypeScript 7 is parallel type checking, which dramatically improves overall check time.
However, parallelism introduces a challenge: when different type-checkers visit nodes, types, and symbols in different orders, the internal IDs assigned to these constructs become non-deterministic.
This in turn leads to confusing non-deterministic output, where two files with identical contents in the same program can produce different declaration files, or even calculate different errors when analyzing the same file.
To fix this, TypeScript 7.0 sorts its internal objects (e.g. types and symbols) according to a deterministic algorithm based on the content of the object.
This ensures that all checkers encounter the same object order regardless of how and when they were created.
As a consequence, in the given example, TypeScript 7 will always print 100 | 500, removing the ordering instability entirely.
这意味着 TypeScript 6 和 7 有时会显示不同的顺序。虽然这些顺序的变化几乎总是无害的,但如果你在比较不同运行的编译器输出(例如,检查 6.0 与 7.0 版本生成的声明文件),这些不同的顺序可能会产生很多干扰,使得评估正确性变得困难。不过,有时你可能会遇到顺序的变化导致类型错误出现或消失,这可能更加令人困惑。
🌐 This means that TypeScript 6 and 7 can and do sometimes display different ordering. While these ordering changes are almost always benign, if you’re comparing compiler outputs between runs (for example, checking emitted declaration files in 6.0 vs 7.0), these different orderings can produce a lot of noise that makes it difficult to assess correctness. Occasionally though, you may witness a change in ordering that causes a type error to appear or disappear, which can be even more confusing.
为帮助解决这种情况,在 6.0 中,你可以指定新的 --stableTypeOrdering 标志。这使得 6.0 的类型排序行为与 7.0 匹配,从而减少两个代码库之间的差异。请注意,我们不一定鼓励一直使用此标志,因为它可能会显著减慢类型检查速度(根据代码库不同,最多可达 25%)。
🌐 To help with this situation, in 6.0, you can specify the new --stableTypeOrdering flag.
This makes 6.0’s type ordering behavior match 7.0’s, reducing the number of differences between the two codebases.
Note that we don’t necessarily encourage using this flag all the time as it can add a substantial slowdown to type-checking (up to 25% depending on codebase).
如果你在使用 --stableTypeOrdering 时遇到类型错误,这通常是由于推断差异引起的。
在没有 --stableTypeOrdering 的情况下之前的推断恰好能根据你程序中类型的当前顺序工作。
为此,你通常会受益于在某个地方提供显式类型。
通常,这将是一个类型参数
🌐 If you encounter a type error using --stableTypeOrdering, this is typically due to inference differences.
The previous inference without --stableTypeOrdering happened to work based on the current ordering of types in your program.
To help with this, you’ll often benefit from providing an explicit type somewhere.
Often, this will be a type argument
diff- someFunctionCall(/*...*/);+ someFunctionCall<SomeExplicitType>(/*...*/);
或者是你打算传入调用的参数的变量注解。
🌐 or a variable annotation for an argument you intend to pass into a call.
diff- const someVariable = { /*... some complex object ...*/ };+ const someVariable: SomeExplicitType = { /*... some complex object ...*/ };someFunctionCall(someVariable);
请注意,此标志仅用于帮助诊断 6.0 与 7.0 之间的差异——它并不打算作为长期功能使用
target 和 lib 的 es2025 选项
🌐 es2025 option for target and lib
TypeScript 6.0 为 target 和 lib 都添加了对 es2025 选项的支持。虽然 ES2025 中没有新的 JavaScript 语言特性,但这个新目标为内置 API(例如 RegExp.escape)添加了新类型,并将一些声明从 esnext 移动到了 es2025(例如 Promise.try、Iterator 方法,以及 Set 方法)。启用新目标 的工作得到了 Kenta Moriuchi 的贡献。
🌐 TypeScript 6.0 adds support for the es2025 option for both target and lib.
While there are no new JavaScript language features in ES2025, this new target adds new types for built-in APIs (e.g. RegExp.escape), and moves a few declarations from esnext into es2025 (e.g. Promise.try, Iterator methods, and Set methods).
Work to enable the new target was contributed thanks to Kenta Moriuchi.
Temporal 的新类型
🌐 New Types for Temporal
备受期待的 Temporal 提案 已经达到了第 4 阶段,并将成为未来 ECMAScript 标准的一部分。TypeScript 6.0 现在包含了 Temporal API 的内置类型,因此你今天就可以通过 --target esnext 或 "lib": ["esnext"](或更细粒度的 esnext.temporal)在 TypeScript 代码中开始使用它。
🌐 The long-awaited Temporal proposal has reached stage 4 and will be part of a future ECMAScript standard.
TypeScript 6.0 now includes built-in types for the Temporal API, so you can start using it in your TypeScript code today via --target esnext or "lib": ["esnext"] (or the more-granular esnext.temporal).
tslet yesterday = Temporal.Now.instant().subtract({hours: 24,});let tomorrow = Temporal.Now.instant().add({hours: 24,});console.log(`Yesterday: ${yesterday}`);console.log(`Tomorrow: ${tomorrow}`);
Temporal 已经可以在多个运行时中使用,并且随着进入第4阶段,它现在正式成为 JavaScript 语言的一部分。 关于 Temporal API 的文档可在 MDN 上查阅。
🌐 Temporal is already usable in several runtimes, and with stage 4 status it is now officially part of the JavaScript language. Documentation on the Temporal APIs is available on MDN.
这个作品 感谢 GitHub 用户 Renegade334 的贡献。
“upsert” 方法的新类型(又名 getOrInsert)
🌐 New Types for “upsert” Methods (a.k.a. getOrInsert)
Map 的一个常见模式是检查一个键是否存在,如果不存在,则设置并获取一个默认值。
🌐 A common pattern with Maps is to check if a key exists, and if not, set and fetch a default value.
tsfunction processOptions(compilerOptions: Map<string, unknown>) {let strictValue: unknown;if (compilerOptions.has("strict")) {strictValue = compilerOptions.get("strict");}else {strictValue = true;compilerOptions.set("strict", strictValue);}// ...}
这种模式可能很乏味。ECMAScript 的“upsert”提案 最近达到了第 4 阶段,并在 Map 和 WeakMap 上引入了 2 个新方法:
🌐 This pattern can be tedious.
ECMAScript’s “upsert” proposal recently reached stage 4, and introduces 2 new methods on Map and WeakMap:
getOrInsertgetOrInsertComputed
这些方法已被添加到 esnext 库中,以便你可以立即在 TypeScript 6.0 中使用它们。
🌐 These methods have been added to the esnext lib so that you can start using them immediately in TypeScript 6.0.
使用 getOrInsert,我们可以将上面的代码替换为如下内容:
🌐 With getOrInsert, we can replace our code above with the following:
tsfunction processOptions(compilerOptions: Map<string, unknown>) {let strictValue = compilerOptions.getOrInsert("strict", true);// ...}
getOrInsertComputed 的工作方式类似,但适用于默认值可能计算成本高的情况(例如需要大量计算、分配,或进行长时间的同步 I/O)。
相反,它接受一个回调函数,只有在键尚不存在时才会调用该回调。
tssomeMap.getOrInsertComputed("someKey", () => {return computeSomeExpensiveValue(/*...*/);});
这个回调函数也会将键作为参数传入,这在默认值基于键的情况下非常有用。
🌐 This callback is also given the key as an argument, which can be useful for cases where the default value is based on the key.
tssomeMap.getOrInsertComputed(someKey, computeSomeExpensiveDefaultValue);function computeSomeExpensiveValue(key: string) {// ...}
这个更新 感谢 GitHub 用户 Renegade334 的贡献。
RegExp.escape
在构建一些要在正则表达式中匹配的字面字符串时,重要的是要对特殊的正则表达式字符如 *、+、?、(、) 等进行转义。RegExp 转义 ECMAScript 提案 已经达到第 4 阶段,并引入了一个新的 RegExp.escape 函数来为你处理这个问题。
🌐 When constructing some literal string to match within a regular expression, it is important to escape special regular expression characters like *, +, ?, (, ), etc.
The RegExp Escaping ECMAScript proposal has reached stage 4, and introduces a new RegExp.escape function that takes care of this for you.
tsfunction matchWholeWord(word: string, text: string) {const escapedWord = RegExp.escape(word);const regex = new RegExp(`\\b${escapedWord}\\b`, "g");return text.match(regex);}
RegExp.escape 可在 es2025 库中使用,因此你可以在 TypeScript 6.0 中立即开始使用它。
这项工作 得到了 Kenta Moriuchi 的贡献。
dom 库现在包含 dom.iterable 和 dom.asynciterable
🌐 The dom lib Now Contains dom.iterable and dom.asynciterable
TypeScript 的 lib 选项允许你指定目标运行时环境中有哪些全局声明。一个选项是 dom,表示 Web 环境(即实现了 DOM API 的浏览器)。此前,DOM API 被部分拆分到 dom.iterable 和 dom.asynciterable 中,用于不支持 Iterable 和 AsyncIterable 的环境。这意味着你必须显式添加 dom.iterable,才能在像 NodeList 或 HTMLCollection 这样的 DOM 集合上使用迭代方法。
🌐 TypeScript’s lib option allows you to specify which global declarations your target runtime has.
One option is dom to represent web environments (i.e. browsers, who implement the DOM APIs).
Previously, the DOM APIs were partially split out into dom.iterable and dom.asynciterable for environments that didn’t support Iterables and AsyncIterables.
This meant that you had to explicitly add dom.iterable to use iteration methods on DOM collections like NodeList or HTMLCollection.
在 TypeScript 6.0 中,lib.dom.iterable.d.ts 和 lib.dom.asynciterable.d.ts 的内容已完全包含在 lib.dom.d.ts 中。你仍然可以在配置文件的 "lib" 数组中引用 dom.iterable 和 dom.asynciterable,但它们现在只是空文件。
🌐 In TypeScript 6.0, the contents of lib.dom.iterable.d.ts and lib.dom.asynciterable.d.ts are fully included in lib.dom.d.ts.
You can still reference dom.iterable and dom.asynciterable in your configuration file’s "lib" array, but they are now just empty files.
ts// Before TypeScript 6.0, this required "lib": ["dom", "dom.iterable"]// Now it works with just "lib": ["dom"]for (const element of document.querySelectorAll("div")) {console.log(element.textContent);}
这是一个提高生活质量的改进,消除了一个常见的混淆点,因为没有现代主流浏览器缺少这些功能。如果你之前已经同时包含了 dom 和 dom.iterable,现在你可以简化为只使用 dom。
🌐 This is a quality-of-life improvement that eliminates a common point of confusion, since no major modern browser lacks these capabilities.
If you were already including both dom and dom.iterable, you can now simplify to just dom.
🌐 See more at this issue and its corresponding pull request.
TypeScript 6.0 中的重大更改和废弃功能
🌐 Breaking Changes and Deprecations in TypeScript 6.0
TypeScript 6.0 作为一个重大的过渡版本发布,旨在为开发者准备 TypeScript 7.0——即即将推出的 TypeScript 编译器原生移植版。
虽然 TypeScript 6.0 完全兼容你现有的 TypeScript 知识,并且继续与 TypeScript 5.9 保持 API 兼容,但此版本引入了许多破坏性更改和弃用内容,以反映不断发展的 JavaScript 生态系统,并为 TypeScript 7.0 奠定基础。
🌐 TypeScript 6.0 arrives as a significant transition release, designed to prepare developers for TypeScript 7.0, the upcoming native port of the TypeScript compiler. While TypeScript 6.0 maintains full compatibility with your existing TypeScript knowledge and continues to be API compatible with TypeScript 5.9, this release introduces a number of breaking changes and deprecations that reflect the evolving JavaScript ecosystem and set the stage for TypeScript 7.0.
自从 TypeScript 5.0 发布的两年以来,我们已经看到开发者编写和发布 JavaScript 的方式持续发生变化:
🌐 In the two years since TypeScript 5.0, we’ve seen ongoing shifts in how developers write and ship JavaScript:
- 几乎所有运行时环境现在都是“常青”的。真正的遗留环境(ES5)已极为罕见。
- 打包器和 ESM 已经成为新项目中最常用的模块目标,尽管 CommonJS 仍然是一个主要目标。AMD 和其他浏览器内用户模块系统比 2012 年时要少得多。
- 几乎所有的包都可以通过某种模块系统来使用。UMD 包仍然存在,但几乎没有新的代码仅以全局变量的形式提供。
tsconfig.json几乎是作为一种配置机制普遍存在的。- 对“更严格”类型的需求持续增长。
- TypeScript 的构建性能是首要考虑的问题。尽管 TypeScript 7 带来了提升,性能始终必须保持为关键目标,而那些无法以高效方式支持的选项需要有更充分的理由。
因此,TypeScript 6.0 和 7.0 的设计都是考虑到这些现实的。 对于 TypeScript 6.0,可以通过在 tsconfig 中设置 "ignoreDeprecations": "6.0" 来忽略这些已弃用的内容;但是,请注意,TypeScript 7.0 将不支持任何这些已弃用的选项。
🌐 So TypeScript 6.0 and 7.0 are designed with these realities in mind.
For TypeScript 6.0, these deprecations can be ignored by setting "ignoreDeprecations": "6.0" in your tsconfig; however, note that TypeScript 7.0 will not support any of these deprecated options.
一些必要的调整可以通过 codemod 或工具自动执行。
例如,实验性的 ts5to6 工具 可以自动调整整个代码库中的 baseUrl 和 rootDir。
🌐 Some necessary adjustments can be automatically performed with a codemod or tool.
For example, the experimental ts5to6 tool can automatically adjust baseUrl and rootDir across your codebase.
预先调整
🌐 Up-Front Adjustments
我们将在下面讨论具体的调整,但我们必须注意,某些弃用和行为的变化不一定会有直接指向根本问题的错误消息。因此我们会提前指出,许多项目将至少需要执行以下其中一项操作:
🌐 We’ll cover specific adjustments below, but we have to note that some deprecations and behavior changes do not necessarily have an error message that directly points to the underlying issue. So we’ll note up-front that many projects will need to do at least one of the following:
-
在 tsconfig 中设置
"types"数组,通常设置为"types": ["node"]。"types": ["*"]将恢复 5.9 的行为,但我们建议使用显式数组以提高构建性能和可预测性。如果你看到大量与缺失标识符或未解析的内置模块相关的类型错误,你通常会知道这是问题所在。
-
如果你之前依赖于此被推断出来,请设置
"rootDir": "./src"如果你看到文件被写入到
./dist/src/index.js而不是./dist/index.js,你通常就会知道这是问题所在。
简单的默认更改
🌐 Simple Default Changes
现在,几个编译器选项的默认值已更新,更好地反映了现代开发实践。
🌐 Several compiler options now have updated default values that better reflect modern development practices.
strict现在默认是true: 对更严格类型的需求持续增长,我们发现大多数新项目希望启用strict模式。如果你已经在使用"strict": true,则对你没有任何变化。如果你之前依赖false作为默认值,你需要在你的tsconfig.json中显式设置"strict": false。module默认为esnext:同样地,新的默认值module是esnext,承认 ESM 现在是主流的模块格式。target默认为当前年份的 ES 版本:新的默认target是最新支持的 ECMAScript 规范版本(实际上是一个浮动目标)。目前,该目标是es2025。这反映了大多数开发者正在为常更新的运行时发布代码,并且不需要编译到较旧的 ECMAScript 版本。- 默认情况下
noUncheckedSideEffectImports现在为true:这有助于捕捉仅有副作用导入中的拼写错误问题。 libReplacement现在默认是false: 这个标志之前会导致每次运行时大量模块解析失败,从而增加了我们在--watch和编辑器场景下需要监视的位置数量。在新项目中,libReplacement在其他显式配置之前不会执行任何操作,因此默认关闭它以提升默认性能是合理的。
如果这些新的默认设置破坏了你的项目,你可以在你的 tsconfig.json 中明确指定以前的值。
🌐 If these new defaults break your project, you can specify the previous values explicitly in your tsconfig.json.
rootDir 现在默认是 .
🌐 rootDir now defaults to .
rootDir 控制输出文件相对于输出目录的目录结构。以前,如果未指定 rootDir,则会根据所有非声明输入文件的公共目录来推断。但这通常意味着在不尝试加载和解析项目的情况下,无法知道某个文件是否属于该项目。这也意味着 TypeScript 必须通过分析程序中的每个文件路径来花更多时间推断该公共源目录。
在 TypeScript 6.0 中,默认的 rootDir 将始终是包含 tsconfig.json 文件的目录。rootDir 仅当从命令行使用 tsc 且没有 tsconfig.json 文件时才会被推断。
🌐 In TypeScript 6.0, the default rootDir will always be the directory containing the tsconfig.json file.
rootDir will only be inferred when using tsc from the command line without a tsconfig.json file.
如果你的源文件位于比你的 tsconfig.json 目录更深的任何级别,并且你依赖 TypeScript 来推断源文件的公共根目录,你需要显式设置 rootDir:
🌐 If you have source files any level deeper than your tsconfig.json directory and were relying on TypeScript to infer a common root directory for source files, you’ll need to explicitly set rootDir:
diff{"compilerOptions": {// ...+ "rootDir": "./src"},"include": ["./src"]}
同样,如果你的 tsconfig.json 引用了包含 tsconfig.json 之外的文件,你需要调整你的 rootDir 以包含这些文件。
🌐 Likewise, if your tsconfig.json referenced files outside of the containing tsconfig.json, you would need to adjust your rootDir to include those files.
diff{"compilerOptions": {// ...+ "rootDir": "../src"},"include": ["../src/**/*.tests.ts"]}
🌐 See more at the discussion here and the implementation here.
types 现在默认是 []
🌐 types now defaults to []
在 tsconfig.json 中,compilerOptions 的 types 字段指定了在编译期间要包含在全局作用域中的包列表。通常,node_modules 中的包会通过源代码中的导入自动包含;但为了方便,TypeScript 也会默认包含 node_modules/@types 中的所有包,这样你就可以获取全局声明,例如来自 @types/node 的 process 或 "fs" 模块,或者来自 @types/jest 的 describe 和 it,而无需直接导入它们。
🌐 In a tsconfig.json, the types field of compilerOptions specifies a list of package names to be included in the global scope during compilation.
Typically, packages in node_modules are automatically included via imports in your source code;
but for convenience, TypeScript would also include all packages in node_modules/@types by default, so that you can get global declarations like process or the "fs" module from @types/node, or describe and it from @types/jest, without needing to import them directly.
在某种意义上,之前默认的 types 值是“枚举 node_modules/@types 中的所有内容”。
这可能非常昂贵,因为在现今的普通仓库设置中,可能会通过传递方式拉入上百个 @types 包,尤其是在包含扁平化 node_modules 的多项目工作区中。
现代项目几乎总是只需要 @types/node、@types/jest 或少数其他常见的全局影响包。
🌐 In a sense, the types value previously defaulted to “enumerate everything in node_modules/@types”.
This can be very expensive, as a normal repository setup these days might transitively pull in hundreds of @types packages, especially in multi-project workspaces with flattened node_modules.
Modern projects almost always need only @types/node, @types/jest, or a handful of other common global-affecting packages.
在 TypeScript 6.0 中,默认的 types 值将是 [](一个空数组)。
此更改可以防止项目在构建时无意中加载数百甚至数千个不必要的声明文件。
我们查看的许多项目仅通过适当地设置 types 就将构建时间提高了 20-50%。
🌐 In TypeScript 6.0, the default types value will be [] (an empty array).
This change prevents projects from unintentionally pulling in hundreds or even thousands of unneeded declaration files at build time.
Many projects we’ve looked at have improved their build time anywhere from 20-50% just by setting types appropriately.
这将影响许多项目。 你可能需要添加 "types": ["node"] 或其他几个:
diff{"compilerOptions": {// Explicitly list the @types packages you need+ "types": ["node", "jest"]}}
你也可以指定一个 * 条目来重新启用旧的枚举行为:
🌐 You can also specify a * entry to re-enable the old enumeration behavior:
diff{"compilerOptions": {// Load ALL the types - the default from TypeScript 5.9 and before.+ "types": ["*"]}}
如果你最终遇到如下的新错误信息:
🌐 If you end up with new error messages like the following:
Cannot find module '...' or its corresponding type declarations.Cannot find name 'fs'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.Cannot find name 'path'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.Cannot find name 'Bun'. Do you need to install type definitions for Bun? Try `npm i --save-dev @types/bun` and then add 'bun' to the types field in your tsconfig.Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha` and then add 'jest' or 'mocha' to the types field in your tsconfig.
你很可能需要在你的 types 字段中添加一些条目。
🌐 it’s likely that you need to add some entries to your types field.
🌐 See more at the proposal here along with the implementing pull request here.
已弃用:target: es5
🌐 Deprecated: target: es5
ECMAScript 5 目标曾经很重要,因为它能够支持旧版浏览器;但它的继任者 ECMAScript 2015(ES6)已在十多年前发布,且所有现代浏览器多年来都已支持它。随着 Internet Explorer 的退役,以及常青浏览器的普及,如今几乎没有使用 ES5 输出的场景。
🌐 The ECMAScript 5 target was important for a long time to support legacy browsers; but its successor, ECMAScript 2015 (ES6), was released over a decade ago, and all modern browsers have supported it for many years. With Internet Explorer’s retirement, and the universality of evergreen browsers, there are very few use cases for ES5 output today.
TypeScript 的最低目标现在将是 ES2015,并且 target: es5 选项已被弃用。如果你之前使用的是 target: es5,则需要迁移到更新的目标或使用外部编译器。
如果你仍然需要 ES5 输出,我们建议使用外部编译器直接编译你的 TypeScript 源代码,或对 TypeScript 的输出进行后处理。
🌐 TypeScript’s lowest target will now be ES2015, and the target: es5 option is deprecated. If you were using target: es5, you’ll need to migrate to a newer target or use an external compiler.
If you still need ES5 output, we recommend using an external compiler to either directly compile your TypeScript source, or to post-process TypeScript’s outputs.
已弃用:--downlevelIteration
🌐 Deprecated: --downlevelIteration
--downlevelIteration 仅对 ES5 输出有效,并且由于 --target es5 已被弃用,--downlevelIteration 不再起作用。
微妙地,在 TypeScript 5.9 及更早版本中,使用 --downlevelIteration false 配合 --target es2015 并不会报错,尽管它没有任何效果。在 TypeScript 6.0 中,任何设置 --downlevelIteration 的行为都会导致弃用错误。
🌐 Subtly, using --downlevelIteration false with --target es2015 did not error in TypeScript 5.9 and earlier, even though it had no effect.
In TypeScript 6.0, setting --downlevelIteration at all will lead to a deprecation error.
请参见此处的实现。
🌐 See the implementation here.
已弃用:--moduleResolution node(又名 --moduleResolution node10)
🌐 Deprecated: --moduleResolution node (a.k.a. --moduleResolution node10)
--moduleResolution node 编码了 Node.js 模块解析算法的一个特定版本,该版本最准确地反映了 Node.js 10 的行为。不幸的是,这个目标(及其名称)忽略了自那时以来对 Node.js 解析算法所做的许多更新,它不再能很好地代表现代 Node.js 版本的行为。
在 TypeScript 6.0 中,--moduleResolution node(具体来说是 --moduleResolution node10)已被弃用。使用 --moduleResolution node 的用户如果计划直接针对 Node.js,应通常迁移到 --moduleResolution nodenext;如果计划使用打包工具或 Bun,则应迁移到 --moduleResolution bundler。
🌐 In TypeScript 6.0, --moduleResolution node (specifically, --moduleResolution node10) is deprecated.
Users who were using --moduleResolution node should usually migrate to --moduleResolution nodenext if they plan on targeting Node.js directly, or --moduleResolution bundler if they plan on using a bundler or Bun.
🌐 See more at this issue and its corresponding pull request.
已弃用:module 的 amd、umd 和 systemjs 值
🌐 Deprecated: amd, umd, and systemjs values of module
以下标志值不再受支持
🌐 The following flag values are no longer supported
--module amd--module umd--module systemjs--module none
在 JavaScript 模块的早期阶段,当浏览器缺乏原生模块支持时,AMD、UMD 和 SystemJS 都很重要。 “none”的语义从未明确定义,通常导致混淆。 如今,ESM 在浏览器和 Node.js 中得到了普遍支持,而 import maps 和打包工具已成为弥补差距的常用方式。 如果你仍在使用这些模块系统,考虑迁移到适当的 ECMAScript 模块输出目标,采用打包工具或不同的编译器,或者在可以迁移之前继续使用 TypeScript 5.x。
🌐 AMD, UMD, and SystemJS were important during the early days of JavaScript modules when browsers lacked native module support. The semantics of “none” were never well-defined and often led to confusion. Today, ESM is universally supported in browsers and Node.js, and both import maps and bundlers have become favored ways for filling in the gaps. If you’re still targeting these module systems, consider migrating to an appropriate ECMAScript module-emitting target, adopt a bundler or different compiler, or stay on TypeScript 5.x until you can migrate.
这也意味着对 amd-module 指令的支持将被取消,该指令将不再起任何作用。
🌐 This also implies dropped support for the amd-module directive, which will no longer have any effect.
🌐 See more at the proposal issue along with the implementing pull request.
已弃用:--baseUrl
🌐 Deprecated: --baseUrl
baseUrl 选项最常与 paths 一起使用,通常用作 paths 中每个值的前缀。不幸的是,baseUrl 也被认为是模块解析的查找根。
🌐 The baseUrl option is most-commonly used in conjunction with paths, and is typically used as a prefix for every value in paths.
Unfortunately, baseUrl is also considered a look-up root for module resolution.
例如,给定以下 tsconfig.json
🌐 For example, given the following tsconfig.json
json{"compilerOptions": {// ..."baseUrl": "./src","paths": {"@app/*": ["app/*"],"@lib/*": ["lib/*"]}}}
以及像这样的导入
🌐 and an import like
tsimport * as someModule from "someModule.js";
即使开发者只打算为以 @app/ 和 @lib/ 开头的模块添加映射,TypeScript 很可能也会将其解析为 src/someModule.js。
🌐 TypeScript will probably resolve this to src/someModule.js, even if the developer only intended to add mappings for modules starting with @app/ and @lib/.
在最好的情况下,这也常常导致打包工具会忽略的“看起来更差”的路径;但这通常意味着许多在运行时永远无法工作的导入路径在 TypeScript 中被认为是“没问题”的。
🌐 In the best case, this also often leads to “worse-looking” paths that bundlers would ignore; but it often meant that that many import paths that would never have worked at runtime are considered “just fine” by TypeScript.
path 映射已经很久不需要指定 baseUrl,实际上,大多数使用 baseUrl 的项目仅将其用作 paths 条目的前缀。
在 TypeScript 6.0 中,baseUrl 已被弃用,并将不再被视为模块解析的查找根。
使用 baseUrl 作为路径映射条目前缀的开发者只需移除 baseUrl 并将前缀添加到他们的 paths 条目中:
🌐 Developers who used baseUrl as a prefix for path-mapping entries can simply remove baseUrl and add the prefix to their paths entries:
diff{"compilerOptions": {// ...- "baseUrl": "./src","paths": {- "@app/*": ["app/*"],- "@lib/*": ["lib/*"]+ "@app/*": ["./src/app/*"],+ "@lib/*": ["./src/lib/*"]}}}
实际上使用 baseUrl 作为查找根的开发者也可以添加显式路径映射以保留旧的行为:
🌐 Developers who actually did use baseUrl as a look-up root can also add an explicit path mapping to preserve the old behavior:
json{"compilerOptions": {// ..."paths": {// A new catch-all that replaces the baseUrl:"*": ["./src/*"],// Every other path now has an explicit common prefix:"@app/*": ["./src/app/*"],"@lib/*": ["./src/lib/*"],}}}
然而,这种情况非常罕见。我们建议大多数开发者直接移除 baseUrl,并在他们的 paths 条目中添加适当的前缀。
🌐 However, this is extremely rare.
We recommend most developers simply remove baseUrl and add the appropriate prefixes to their paths entries.
🌐 See more at this issue and the corresponding pull request.
已弃用:--moduleResolution classic
🌐 Deprecated: --moduleResolution classic
moduleResolution: classic 设置已被移除。
classic 解析策略是 TypeScript 最初的模块解析算法,并早于 Node.js 的解析算法成为事实标准。
如今,所有实际使用场景都可以通过 nodenext 或 bundler 实现。
如果你在使用 classic,请迁移到这些现代解析策略之一。
🌐 The moduleResolution: classic setting has been removed.
The classic resolution strategy was TypeScript’s original module resolution algorithm, and predates Node.js’s resolution algorithm becoming a de facto standard.
Today, all practical use cases are served by nodenext or bundler.
If you were using classic, migrate to one of these modern resolution strategies.
🌐 See more at this issue and the implementing pull request.
已弃用:--esModuleInterop false 和 --allowSyntheticDefaultImports false
🌐 Deprecated: --esModuleInterop false and --allowSyntheticDefaultImports false
以下设置不再可以设置为 false:
🌐 The following settings can no longer be set to false:
esModuleInteropallowSyntheticDefaultImports
esModuleInterop 和 allowSyntheticDefaultImports 最初是可选择的,以避免破坏现有项目。然而,它们启用的行为多年来一直是推荐的默认设置。将它们设置为 false 通常会在从 ESM 使用 CommonJS 模块时导致微妙的运行时问题。在 TypeScript 6.0 中,更安全的互操作行为将始终启用。
如果你的导入依赖于旧的行为,你可能需要调整它们:
🌐 If you have imports that rely on the old behavior, you may need to adjust them:
ts// Before (with esModuleInterop: false)import * as express from "express";// After (with esModuleInterop always enabled)import express from "express";
🌐 See more at this issue and its implementing pull request.
已弃用:--alwaysStrict false
🌐 Deprecated: --alwaysStrict false
alwaysStrict 标志是指 "use strict"; 指令的推断和发出。在 TypeScript 6.0 中,所有代码都将被假定为处于 JavaScript 严格模式,这是一组 JS 语义,最明显地影响围绕保留字的语法边缘情况。如果你的“宽松模式”代码使用了像 await、static、private 或 public 这样的保留字作为常规标识符,你需要重命名它们。如果你依赖于非严格代码中 this 含义的微妙语义,你也可能需要调整你的代码。
🌐 The alwaysStrict flag refers to inference and emit of the "use strict"; directive.
In TypeScript 6.0, all code will be assumed to be in JavaScript strict mode, which is a set of JS semantics that most-noticeably affects syntactic corner cases around reserved words.
If you have “sloppy mode” code that uses reserved words like await, static, private, or public as regular identifiers, you’ll need to rename them.
If you relied on subtle semantics around the meaning of this in non-strict code, you may need to adjust your code as well.
🌐 See more at this issue and its corresponding pull request.
已弃用:outFile
🌐 Deprecated: outFile
--outFile 选项已从 TypeScript 6.0 中移除。该选项最初用于将多个输入文件合并为一个输出文件。然而,像 Webpack、Rollup、esbuild、Vite、Parcel 等外部打包工具现在可以更快、更好地完成这项工作,并且具有更多的可配置性。移除此选项简化了实现,并让我们能够专注于 TypeScript 的核心功能:类型检查和声明文件生成。如果你当前正在使用 --outFile,你需要迁移到外部打包工具。大多数现代打包工具开箱即提供优秀的 TypeScript 支持。
🌐 The --outFile option has been removed from TypeScript 6.0. This option was originally designed to concatenate multiple input files into a single output file. However, external bundlers like Webpack, Rollup, esbuild, Vite, Parcel, and others now do this job faster, better, and with far more configurability. Removing this option simplifies the implementation and allows us to focus on what TypeScript does best: type-checking and declaration emit. If you’re currently using --outFile, you’ll need to migrate to an external bundler. Most modern bundlers have excellent TypeScript support out of the box.
已弃用:命名空间的旧 module 语法
🌐 Deprecated: legacy module Syntax for namespaces
TypeScript 的早期版本使用 module 关键字来声明命名空间:
🌐 Early versions of TypeScript used the module keyword to declare namespaces:
ts// ❌ Deprecated syntax - now an errormodule Foo {export const bar = 10;}
这种语法后来使用 namespace 关键字被别名为现代首选形式:
🌐 This syntax was later aliased to the modern preferred form using the namespace keyword:
ts// ✅ The correct syntaxnamespace Foo {export const bar = 10;}
当引入 namespace 时,module 语法只是被简单地不推荐使用。几年前,TypeScript 语言服务开始将该关键字标记为已弃用,建议使用 namespace 代替。
🌐 When namespace was introduced, the module syntax was simply discouraged.
A few years ago, the TypeScript language service started marking the keyword as deprecated, suggesting namespace in its place.
在 TypeScript 6.0 中,在期望 namespace 的地方使用 module 现在是严格弃用的。
这个更改是必要的,因为 module 块是一个潜在的 ECMAScript 提案,可能与旧的 TypeScript 语法冲突。
🌐 In TypeScript 6.0, using module where namespace is expected is now a hard deprecation.
This change is necessary because module blocks are a potential ECMAScript proposal that would conflict with the legacy TypeScript syntax.
环境模块声明形式仍然得到完全支持:
🌐 The ambient module declaration form remains fully supported:
ts// ✅ Still works perfectlydeclare module "some-module" {export function doSomething(): void;}
🌐 See this issue and its corresponding pull request for more details.
已弃用:导入中的 asserts 关键字
🌐 Deprecated: asserts Keyword on Imports
asserts 关键字是通过导入断言提案被提出给 JavaScript 语言的;然而,该提案最终演变成了 导入属性提案,它使用 with 关键字而不是 asserts。
🌐 The asserts keyword was proposed to the JavaScript language via the import assertions proposal;
however, the proposal eventually morphed into the import attributes proposal, which uses the with keyword instead of asserts.
因此,在 TypeScript 6.0 中,asserts 语法已被弃用,使用它将导致错误:
🌐 Thus, the asserts syntax is now deprecated in TypeScript 6.0, and using it will lead to an error:
ts// ❌ Deprecated syntax - now an error.import blob from "./blahb.json" asserts { type: "json" }// ~~~~~~~// error: Import assertions have been replaced by import attributes. Use 'with' instead of 'asserts'.
相反,使用 with 语法来导入属性:
🌐 Instead, use the with syntax for import attributes:
ts// ✅ Works with the new import attributes syntax.import blob from "./blahb.json" with { type: "json" }
🌐 See more at this issue and its corresponding pull request.
已弃用:no-default-lib 指令
🌐 Deprecated: no-default-lib Directives
/// <reference no-default-lib="true"/> 指令在很大程度上被误解和滥用。在 TypeScript 6.0 中,该指令不再受支持。如果你曾经使用过它,建议改用 --noLib 或 --libReplacement。
🌐 The /// <reference no-default-lib="true"/> directive has been largely misunderstood and misused.
In TypeScript 6.0, this directive is no longer supported.
If you were using it, consider using --noLib or --libReplacement instead.
当 tsconfig.json 存在时指定命令行文件现在会导致错误
🌐 Specifying Command-Line Files When tsconfig.json Exists is Now an Error
目前,如果你在一个存在 tsconfig.json 的文件夹中运行 tsc foo.ts,配置文件会被完全忽略。如果你期望检查和输出选项应用于输入文件,这通常会非常令人困惑。
🌐 Currently, if you run tsc foo.ts in a folder where a tsconfig.json exists, the config file is completely ignored.
This was often very confusing if you expected checking and emit options to apply to the input file.
在 TypeScript 6.0 中,如果你在包含 tsconfig.json 的目录中使用文件参数运行 tsc,将会出现错误以明确此行为:
🌐 In TypeScript 6.0, if you run tsc with file arguments in a directory containing a tsconfig.json, an error will be issued to make this behavior explicit:
error TS5112: tsconfig.json is present but will not be loaded if files are specified on commandline. Use '--ignoreConfig' to skip this error.
如果你希望忽略 tsconfig.json 并仅使用 TypeScript 的默认设置编译 foo.ts,你可以使用新的 --ignoreConfig 标志。
🌐 If it is the case that you wanted to ignore the tsconfig.json and just compile foo.ts with TypeScript’s defaults, you can use the new --ignoreConfig flag.
shtsc --ignoreConfig foo.ts
🌐 See more at this issue and its corresponding pull request.
为 TypeScript 7.0 做准备
🌐 Preparing for TypeScript 7.0
TypeScript 6.0 被设计为过渡版本。虽然在 TypeScript 6.0 中被废弃的选项在设置 "ignoreDeprecations": "6.0" 时仍然可以正常工作,不会报错,但这些选项将在 TypeScript 7.0(原生 TypeScript 移植版)中完全移除。如果在升级到 TypeScript 6.0 后看到弃用警告,我们强烈建议在采用 TypeScript 7.0(或尝试 native previews)之前先处理这些警告。
🌐 TypeScript 6.0 is designed as a transition release.
While options deprecated in TypeScript 6.0 will continue to work without errors when "ignoreDeprecations": "6.0" is set, those options will be removed entirely in TypeScript 7.0 (the native TypeScript port).
If you’re seeing deprecation warnings after upgrading to TypeScript 6.0, we strongly recommend addressing them before adopting TypeScript 7.0 (or trying native previews) in your project.