介绍
随着 TypeScript 代码库的增长,单一的 tsconfig.json 方法会崩溃。每次调用 tsc 都会进行类型检查并发出整个项目 - 即使在大型 monorepos 中使用 --noEmit ,这个过程也可能需要几分钟的时间。更糟糕的是,没有模块边界,任何文件都可以导入任何其他文件,从而创建难以重构的混乱依赖关系图。 TypeScript 项目参考 通过允许您将代码库拆分为独立的子项目(每个子项目都有自己的 tsconfig.json)来解决此问题,从而实现增量构建、强制执行 API 边界以及显着加快类型检查速度。
什么是项目参考?
项目引用声明一个 TypeScript 项目依赖于另一个项目。每个子项目必须在其 tsconfig.json 中设置 composite: true,并且使用项目在 references 数组中列出其依赖项:
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"rootDir": "src",
"outDir": "dist"
}
}
{
"references": [
{ "path": "../packages/core" },
{ "path": "../packages/utils" }
]
}
构建时,TypeScript 首先构建引用的项目(按拓扑顺序),生成父项目使用的 .d.ts 和 .js 输出。这强制了一个清晰的、非循环的依赖关系图——如果包 A 引用包 B,那么 B 就不能引用 A。任何创建循环依赖关系的尝试都会产生编译时错误。
组合项目和构建模式
复合项目 (composite: true) 是设计供其他项目引用的项目。它需要 declaration: true、rootDir 和 outDir。强烈建议启用 declarationMap: true — 它会生成 .d.ts.map 文件,允许编辑器工具(如“转到定义”)直接导航到原始 .ts 源而不是 .d.ts 声明文件。
构建模式命令 tsc --build (或 tsc -b)智能地处理整个项目图:
# Build all projects and their dependencies
tsc -b
# Force rebuild all projects
tsc -b --force
# Clean build outputs
tsc -b --clean
# Dry run — show what would be built
tsc -b --dry
构建模式使用 .tsbuildinfo 文件来跟踪文件哈希和依赖关系。在后续运行中,它会跳过输入未更改的项目,从而导致大型 monorepos 的构建时间减少 50–90%。 incremental: true 选项由 composite 隐含,但您可以使用 tsBuildInfoFile 控制构建信息文件的写入位置。
单一仓库集成
项目参考与 monorepo 工具自然集成。典型的结构如下所示:
packages/
core/ tsconfig.json (composite: true)
utils/ tsconfig.json (composite: true)
apps/
web/ tsconfig.json (references: [core, utils])
api/ tsconfig.json (references: [core, utils])
tsconfig.base.json
不同的 monorepo 工具提供不同级别的支持:
| 工具 | 支持 |
|---|---|
| npm/pnpm/yarn 工作区 | 效果很好;在根 tsconfig.json 中声明引用 |
| 涡轮增压 | 通过 inputs 和 dependsOn 提供本机支持 |
| Nx | 自动检测项目参考;并行化构建 |
| 勒纳 | 需要手动配置 |
声明图和开发者经验
最有影响力但未充分利用的功能之一是声明映射。当您导航到消费者项目中的类型定义(例如,VS Code 的“转到定义”)时,如果没有声明映射,您将进入 .d.ts 文件,该文件仅包含类型签名,而不包含实现。使用 declarationMap: true,您可以直接跳转到原始 .ts 源:
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"sourceMap": true
}
}
声明映射的运行时开销为零——它们仅被编辑器工具消耗。与 sourceMap: true 相结合,它们提供了从开发到生产的完整调试体验。
CI优化
项目参考的真正回报来自 CI。通过在运行之间缓存 .tsbuildinfo 文件(使用 @actions/cache 或类似文件),您可以在管道执行之间保留增量构建信息:
# GitHub Actions — cache .tsbuildinfo files
- uses: actions/cache@v3
with:
path: "**/*.tsbuildinfo"
key: tsbuildinfo-${{ runner.os }}-${{ hashFiles('**/tsconfig*.json') }}
对于选择性类型检查,请使用 tsc -b --noEmit — 此类型仅检查自上次构建以来发生更改的项目,而不是整个代码库。为主分支构建保留 --force ;依赖增量模式进行拉取请求 CI。对于非常大的单一存储库,像 nx affected 这样的工具可以进一步将范围缩小到受给定变更直接影响的项目。
结论
TypeScript 项目参考解决了大型 TypeScript 代码库的扩展问题。首先将您的项目分成 2-3 个逻辑包 - 一个核心类型包、一个实用程序包和您的应用程序代码。将 composite: true 与声明映射结合使用以获得良好的开发人员体验,利用 tsc -b 进行快速增量构建,并在 CI 中缓存 .tsbuildinfo 文件以跨管道运行扩展这些优势。 Turborepo 和 Nx 等工具通过缓存和并行执行增强项目引用,使它们在 monorepo 设置中更加强大。

