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 团队认为 preserveValueImports 和 importsNotUsedAsValues 是两个独立的旧开关,语义重叠且容易混淆。verbatimModuleSyntax 统一了它们:
- 更清晰的语义:你写什么 import,输出就保留什么
- 与
import type配合更好:明确区分值导入和类型导入 - 与
isolatedModules的交互更明确
迁移方式
// tsconfig.json
{
"compilerOptions": {
- "preserveValueImports": true
+ "verbatimModuleSyntax": true
}
}
迁移后,纯类型导入必须使用 import type,否则编译器会报错提示你显式标注。
与 importsNotUsedAsValues 的关系
| 选项 | 语义 | 状态 |
|---|---|---|
preserveValueImports | 强制保留所有值导入 | 已废弃 |
importsNotUsedAsValues | 三选一:remove / preserve / error | 已废弃 |
verbatimModuleSyntax | 统一替代以上两者 | 当前推荐 |
两者都被 verbatimModuleSyntax 取代。
与 isolatedModules 的交集
当 preserveValueImports 和 isolatedModules 组合时,纯类型导入必须明确标成 import type,因为单文件编译器无法判断导入是值还是类型。
边界与常见误解
- 不是”保留所有 import”:
import type仍然会被删除,它只影响值导入 - 不解决循环依赖:保留导入不会修复循环引用问题
- 不是性能优化:保留更多导入可能增加 bundle 体积,需配合 Tree Shaking
参考信息
- TSConfig
preserveValueImports: https://www.typescriptlang.org/tsconfig/preserveValueImports.html