TypeScript
TypeScript 是 monorepo 中一个出色的工具,允许团队安全地向其 JavaScript 代码添加类型。虽然设置过程有些复杂,但本指南将引导您完成大多数用例中 TypeScript 设置的重要部分。
本指南假定您正在使用最新版本的 TypeScript,并使用了一些仅在这些版本中可用的功能。如果您无法使用这些版本的功能,则可能需要调整本页上的指导。
共享 tsconfig.json
您希望在 TypeScript 配置中构建一致性,以便您的整个仓库可以使用出色的默认设置,并且您的其他开发人员可以知道在工作区中编写代码时会发生什么。
TypeScript 的 tsconfig.json
设置了 TypeScript 编译器的配置,并具有一个 extends
键,您将使用它在整个工作区中共享配置。
本指南将使用 create-turbo
作为示例。
使用基础 tsconfig
文件
在 packages/typescript-config
内部,您有几个 json
文件,这些文件表示您可能希望在各种包中配置 TypeScript 的不同方式。base.json
文件被工作区中所有其他 tsconfig.json
文件扩展,如下所示
tsconfig
选项参考
创建包的其余部分
此包中的其他 tsconfig
文件使用 extends
键从基本配置开始,并为特定类型的项目进行自定义,例如 Next.js (nextjs.json
) 和 React 库 (react-library.json
)。
在 package.json
内部,命名包以便可以在工作区的其余部分中引用它
构建 TypeScript 包
使用配置包
首先,将 @repo/typescript-config
包安装到您的包中
然后,从 @repo/typescript-config
包扩展包的 tsconfig.json
。在此示例中,web
包是 Next.js 应用程序
创建包的入口点
首先,确保您的代码使用 tsc
编译,以便会有一个 dist
目录。您需要一个 build
脚本以及一个 dev
脚本
然后,在 package.json
中设置包的入口点,以便其他包可以使用编译后的代码
以这种方式设置 exports
有几个优点
- 使用
types
字段允许tsserver
使用src
中的代码作为代码类型的真实来源。您的编辑器将始终与代码中的最新接口保持同步。 - 您可以快速向包添加新的入口点,而无需创建 危险的桶文件。
- 您将在编辑器中收到跨包边界的导入的自动导入建议。
如果您要发布包,则不能在 types
中使用对源代码的引用,因为只有编译后的代码会发布到 npm。您需要生成并引用声明文件和源映射。
Lint 你的代码库
要使用 TypeScript 作为 linter,您可以使用 Turborepo 的缓存和并行化来快速检查整个工作区的类型。
首先,向任何您要检查类型的包添加 check-types
脚本
然后,在 turbo.json
中创建一个 check-types
任务。从 配置任务指南 中,我们可以使任务并行运行,同时使用 Transit Node 尊重来自其他包的源代码更改


然后,使用 turbo check-types
运行您的任务。
最佳实践
使用 tsc
编译您的包
对于 内部包,我们建议您尽可能使用 tsc
编译您的 TypeScript 库。虽然您可以使用 bundler,但这不是必需的,并且会增加构建过程的额外复杂性。此外,捆绑库可能会在代码到达应用程序的 bundler 之前对其进行修改,从而导致难以调试的问题。
在包边界之间启用跳转到定义
“跳转到定义”是一种编辑器功能,用于通过单击或热键快速导航到符号(如变量或函数)的原始声明或定义。正确配置 TypeScript 后,您可以轻松地跨 内部包 导航。
即时包
来自 即时包 的导出将自动将您带到原始 TypeScript 源代码。跳转到定义将按预期工作。
已编译的包
来自 已编译的包 的导出需要使用 declaration
和 declarationMap
配置才能使跳转到定义起作用。在您为包启用这两个配置后,使用 tsc
编译包,并打开输出目录以查找声明文件和源映射。
有了这两个文件,您的编辑器现在将导航到原始源代码。
使用 Node.js 子路径导入而不是 TypeScript 编译器 paths
可以使用 TypeScript 编译器的 paths
选项在您的包中创建绝对导入,但是当使用 即时包 时,这些路径可能会导致编译失败。从 TypeScript 5.4 开始,您可以使用 Node.js 子路径导入 来获得更强大的解决方案。
即时包
在 即时包 中,imports
必须以包中的源代码为目标,因为不会创建像 dist
这样的构建输出。
已编译的包
在 已编译的包 中,imports
以包的构建输出为目标。
您可能不需要项目根目录中的 tsconfig.json
文件
正如构建你的仓库指南 中提到的,您希望将工具中的每个包都视为其自己的单元。这意味着每个包都应该有自己的 tsconfig.json
来使用,而不是引用项目根目录中的 tsconfig.json
。遵循此实践将使 Turborepo 更容易缓存您的类型检查任务,从而简化您的配置。
您可能希望在工作区根目录中拥有 tsconfig.json
的唯一情况是为不在包中的 TypeScript 文件设置配置。例如,如果您有一个用 TypeScript 编写的脚本,需要从根目录运行,您可能需要该文件的 tsconfig.json
。
但是,也不鼓励这种做法,因为工作区根目录中的任何更改都将导致所有任务错过缓存。相反,请将这些脚本移动到仓库中的其他目录。
您可能不需要 TypeScript 项目引用
我们不建议使用 TypeScript 项目引用,因为它们既引入了另一个配置点,又为您的工作区引入了另一个缓存层。这两者都可能在您的仓库中引起问题,但几乎没有好处,因此我们建议在使用 Turborepo 时避免使用它们。
局限性
您的编辑器不会使用包的 TypeScript 版本
tsserver
无法为代码编辑器中的不同包使用不同的 TypeScript 版本。相反,它将发现特定版本并在所有地方使用它。
这可能会导致编辑器中显示的 lint 错误与您运行 tsc
脚本来检查类型时显示的错误之间存在差异。如果这对您来说是一个问题,请考虑保持 TypeScript 依赖项的版本相同。