引言:为什么 @types/* 的问题连经验丰富的开发者都感到头疼?
你是否曾经花了一个小时调试一个错误,而最终发现只是由于 @types/* 包在 package.json 中的位置不正确?如果是的话——你并不孤单。问题 “如何决定 @types/* 是放在 dependencies 还是 devDependencies?” 在 Stack Overflow 上获得了数千次浏览,并成为 TypeScript 社区真正的痛点。
看起来很简单,不是吗?把类型扔进 devDependencies 就完事了。但事情没那么简单。当你的项目开始增长,引入第三方库、单体仓库和 CI/CD 流水线时,类型放置不当可能导致致命的构建错误、生产环境中的意外崩溃,或者更糟的是,悄无声息地丢失类型检查。
在本文中,我们将分析处理 @types/* 时最常见的 5 个错误,学习如何基于真实场景做出正确决策,并制定一个检查清单来保护你免受问题困扰。准备好了吗?我们开始吧!
错误 #1:“所有 @types/* 始终放在 devDependencies”——这个误区会破坏构建
互联网上最流行的建议是:“类型不是运行时代码,因此它们应该始终放在 devDependencies 中”。这在 90% 的情况下确实是正确的。但有一个重要的例外经常被遗忘。
何时 devDependencies 是正确的选择
如果你正在编写一个 应用程序(Express 网络服务器、React 前端、命令行工具),那么所有 @types/* 都可以放心地放入 devDependencies。你的最终用户不会编译 TypeScript——他们运行的是已经编译好的 JavaScript。类型只在你开发时需要。
// Express 应用程序的示例{ "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.11.0", "typescript": "^5.3.3" }}何时 devDependencies 是致命错误
现在想象一下:你正在开发一个 库,它导出 TypeScript 类型供外部使用者使用。如果你的库的类型依赖于 @types/express,而你把它放在了 devDependencies 中,那么安装了你的库的用户 将不会 自动获得这些类型。他们的 IDE 会开始显示红色下划线。
// ❌ 对于导出类型的库来说不正确{ "devDependencies": { "@types/express": "^4.17.21" // 用户将看不到这些类型! }}
// ✅ 正确{ "dependencies": { "@types/express": "^4.17.21" // 类型将对使用者可用 }}黄金法则: 如果你的库 重新导出 来自 @types/* 包的类型,或者在公共 API 中使用它们,那么这个包应该放在 dependencies 中。如果类型仅在内部使用——则放在 devDependencies 中。
错误 #2:忽略“在代码中使用”和“在类型中使用”之间的区别
许多开发者会混淆:“我导入了 Request 来自 express,所以 express 应该放在 dependencies 中”。这对于 express 包本身是正确的,但对于它的类型来说并非如此。
让我们通过一个具体例子来分析。使用 @types/lodash 包有三种场景:
- 场景 A: 你写
import _ from 'lodash'并使用_.chunk()。类型仅用于编译——devDependencies。 - 场景 B: 你创建一个函数
function mySort(arr: T[]): T[]并在内部使用_.orderBy。类型不会暴露出去——devDependencies。 - 场景 C: 你写
export function proc