TypeScript 中的 preserveValueImports(已废弃)

说明 preserveValueImports 曾经为什么要强制保留看起来未使用的值导入,以及它为什么已被 verbatimModuleSyntax 取代。

#tech / dev #resource / typescript #type / concept #status / growing

[!info] related notes

TypeScript 中的 preserveValueImports(已废弃)

一句话定义

preserveValueImports 是 TypeScript 3.8 引入的编译器选项(已废弃),用于强制保留那些看起来未被直接使用但运行时实际需要的值导入。

当前状态

TypeScript 官方 TSConfig 文档明确标注:

  • Deprecated in favor of verbatimModuleSyntax

新项目应直接使用 verbatimModuleSyntax

核心机制 / 工作原理

作用

默认情况下,TypeScript 会把”看起来没用到”的 import 从输出 JS 中删除。preserveValueImports: true 告诉编译器:保留所有非 type-only 的 import,即使它们在当前文件中没有被引用。

为什么需要它

某些场景下,import 看起来”未使用”但运行时实际需要:

  • Svelte / Vue 模板:组件在 <script> 中 import,但使用发生在 .svelte / .vue 模板里,TypeScript 看不到
  • 副作用导入import './polyfill' 没有绑定名,但执行时有副作用
  • eval / 运行时反射:运行时通过字符串名访问导入的值

实际代码示例

// tsconfig.json
{
  "compilerOptions": {
    "preserveValueImports": true
  }
}
// input.ts
import { Button } from './components';  // 看似未使用
import './setup';                        // 副作用导入

// 编译输出(preserveValueImports: true)
import { Button } from './components';  // 保留
import './setup';                        // 保留

// 编译输出(preserveValueImports: false,默认)
// 两行都被删除

为什么废弃

TypeScript 团队认为 preserveValueImportsimportsNotUsedAsValues 是两个独立的旧开关,语义重叠且容易混淆。verbatimModuleSyntax 统一了它们:

  • 更清晰的语义:你写什么 import,输出就保留什么
  • import type 配合更好:明确区分值导入和类型导入
  • isolatedModules 的交互更明确

迁移方式

  // tsconfig.json
  {
    "compilerOptions": {
-     "preserveValueImports": true
+     "verbatimModuleSyntax": true
    }
  }

迁移后,纯类型导入必须使用 import type,否则编译器会报错提示你显式标注。

与 importsNotUsedAsValues 的关系

选项语义状态
preserveValueImports强制保留所有值导入已废弃
importsNotUsedAsValues三选一:remove / preserve / error已废弃
verbatimModuleSyntax统一替代以上两者当前推荐

两者都被 verbatimModuleSyntax 取代。

与 isolatedModules 的交集

preserveValueImportsisolatedModules 组合时,纯类型导入必须明确标成 import type,因为单文件编译器无法判断导入是值还是类型。

边界与常见误解

  • 不是”保留所有 import”import type 仍然会被删除,它只影响值导入
  • 不解决循环依赖:保留导入不会修复循环引用问题
  • 不是性能优化:保留更多导入可能增加 bundle 体积,需配合 Tree Shaking

参考信息

创建于 2026/5/15 更新于 2026/5/27