☰
TypeScript 2.6 破坏性改动详解:只写引用检测与环境声明中的导出约束
2026/9/28 8:42:26 网站建设 项目流程
  • 文档
  • 教程

【免费下载链接】TypeScript

TypeScript 使用手册(中文版)翻译。http://www.typescriptlang.org

项目地址:https://gitcode.com/gh_mirrors/typ/TypeScript
点击查看免费下载

本文聚焦 TypeScript 2.6 版本引入的两项破坏性改动:--noUnusedLocals/--noUnusedParameters对"只写不读"声明的全新检测逻辑,以及环境模块(ambient module)声明文件中禁止任意表达式作为导出值的新规则。阅读本文后,你将理解这两项改动的触发条件、报错信息、正确的迁移写法,以及在升级到 TypeScript 2.6 及以上版本时如何快速定位和修复受影响的代码。

只写引用(Write-only)现在会被标记为未使用

TypeScript 2.6 修复了--noUnusedLocals和--noUnusedParameters两个编译选项的实现逻辑。在此之前,这两个选项只检查声明是否被"引用"(reference);从 2.6 开始,它们检查的是声明的值是否被"读取"(read)。任何只被写入、却从未被读取的声明,现在都会被标记为未使用。

选项的语义与默认值

在本仓库的编译选项文档中,这两个选项的定义如下:

选项类型默认值描述
--noUnusedLocalsbooleanfalse若有未使用的局部变量则抛错。
--noUnusedParametersbooleanfalse若有未使用的参数则抛错。

两个选项默认均为关闭状态,可以在命令行或tsconfig.json中显式开启。

触发条件:只写不读的代码

下面这段代码在 TypeScript 2.5 及更早版本中不会产生编译错误,但在启用--noUnusedLocals和--noUnusedParameters的 TypeScript 2.6 中会被标记为未使用:

function f(n: number) { n = 0; } class C { private m: number; constructor() { this.m = 0; } }

分析这段代码:

  • 函数f的参数n只被赋值(n = 0),其值从未在任何地方被读取,因此触发--noUnusedParameters报错;
  • 类C的私有属性m同样只被写入(this.m = 0),从未被读取,因此触发--noUnusedLocals报错。

注意:在 TypeScript 2.6 中,类私有属性的未使用检查归入--noUnusedLocals的管辖范围,因为对于该检查器而言,它们属于"局部"的声明。

这一改动使检查语义从"是否被引用"收紧为"是否被读取":引用(如赋值)不再足以让声明免于未使用报错,只有真正的读取(如参与运算、作为参数传递、被返回等)才能让声明被视为"已使用"。

仅自调用的递归函数被视为未使用

另一个值得注意的边界情况是递归函数。仅在自己的函数体内被调用的递归函数,现在也被视为未使用:

function f() { f(); // Error: 'f' is declared but its value is never read }

函数f唯一的"使用"发生在它自身内部,从外部视角看,这个声明依然没有任何地方读取它的值,因此被标记为未使用。

这一规则与发布说明中描述的"只写的引用现在会被标记未使用"一致:只要声明的值在程序其他部分从未被消费,无论它内部如何自我引用,都会被视为死代码。

修复建议

受影响的代码通常可以通过以下方式修复:

  1. 确实无用的声明直接删除:对于只写不读的参数或局部变量,如果确实不需要,直接删除即可;
  2. 以下划线开头的参数:对于需要保留签名(如实现接口、回调函数)但未使用的参数,使用下划线前缀(如_n)是社区通行的约定,TypeScript 对这类参数不会报未使用错误;
  3. 为属性补充读取点:如果类属性确实需要在后续逻辑中使用,补上读取它的代码即可消除报错。

后续演进:TypeScript 2.8 的调整

需要留意的是,这组选项的检查范围在后续版本仍在演进。本仓库的TypeScript 2.8 破坏性改动文档指出:未使用的类型参数此前在--noUnusedLocals下报告,从 2.8 起改由--noUnusedParameters报告。也就是说,"只读检查"的语义框架在 2.6 建立后,后续版本对报告归属做了进一步细化,升级到 2.8 及以上版本时需要关注这一归类变化。

环境上下文中的导出赋值禁止使用任意表达式

第二项破坏性改动针对环境上下文(ambient context),即声明文件(.d.ts)与declare module环境模块声明中的导出语句。

改动前:任意表达式曾被允许

在 TypeScript 2.5 及更早版本中,下面的写法在环境上下文中不会被标记为错误:

declare module 'foo' { export default 'some' + 'string'; }

为什么被禁止

声明文件和环境模块通常禁止出现表达式,原因在于typeof之类的意图不明确:环境声明只描述类型形状,不包含可执行代码。允许在export default后跟任意表达式,与 TypeScript 在其他环境上下文中处理可执行代码的方式不一致。

因此从 2.6 开始,export default后面任何不是标识符(identifier)或限定名称(qualified name,如ns.name)的内容都会被标记为错误。

正确的声明方式

为具有上述"值形状"的模块编写.d.ts的正确方法如下:

declare module 'foo' { const _default: string; export default _default; }

即:先在环境模块内部用const声明一个带类型的值,再将这个标识符作为默认导出。这样既保留了"默认导出是一个 string 类型的值"的类型语义,又避免了在环境上下文中执行表达式。

对编译器生成与手写声明的影响

关键的一点是:TypeScript 编译器自身生成的声明文件(通过--declaration选项输出)早已采用这种"先声明常量再导出"的形式,因此这项改动只影响手工编写的.d.ts文件。如果你在项目中维护第三方库的类型声明,或使用declare module为无类型的 npm 包补充类型,升级后需要检查环境模块中的export default是否出现了表达式。

关于环境模块声明的基本写法,可以参考仓库中的声明文件介绍与模块声明模板,其中对declare module的适用场景和结构有系统说明。

升级注意事项小结

将项目升级到 TypeScript 2.6(或更高版本)时,建议按以下顺序自查:

  1. 检查编译选项:确认tsconfig.json或命令行中noUnusedLocals/noUnusedParameters的开启状态。由于默认值为false,未显式开启的项目不会受到第一项改动的影响;开启后则需要注意"只写不读"的参数、局部变量和类私有属性会开始报错,仅自调用的递归函数同样如此。
  2. 扫描手写声明文件:搜索.d.ts文件与declare module块中的export default,确认其后是标识符或限定名称,而非字符串拼接、函数调用等任意表达式。
  3. 关注编译器生成物:由--declaration生成的声明文件不受影响,无需修改。

完整的破坏性改动列表可在本仓库的Breaking Changes 总览中查看,TypeScript 2.6 同期引入的其他新特性(如--strictFunctionTypes、// @ts-ignore注释等)可参见TypeScript 2.6 发布说明。

  • 文档
  • 教程

【免费下载链接】TypeScript

TypeScript 使用手册(中文版)翻译。http://www.typescriptlang.org

项目地址:https://gitcode.com/gh_mirrors/typ/TypeScript
点击查看免费下载

相关推荐

上一篇:终极指南:如何3分钟免费实现PotPlayer字幕实时翻译
下一篇:PotPlayer字幕实时翻译终极指南:3分钟免费实现外语视频无障碍观看

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询