惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

程沛权 - 养了三只猫

声画共生:黄贯中的摇滚美学宇宙 适用于 Oxlint 与 Oxfmt 的 Oxc 优先工作流 Vue Picture Cropper 发布 1.x 版本 讲一讲背后的设计理念 年终总结:2025 年的一些回顾和 2026 年的一些小规划 Obsidian x 飞牛 NAS:打造免费的跨平台笔记同步与备份方案 适用于 ESLint V9 的现代化扁平化配置 解决 better-sqlite3 连接 SQLite 时报错 Could not locate the bindings file 本色十年 记录一次 ERR_INCOMPLETE_CHUNKED_ENCODING 的问题排查 使用 remark-directive 为 Unifiedjs 提供 Markdown 视频语法的解析 macOS 基于 Android Studio 修改模拟器 Hosts 给猫儿子的新年礼物 它很喜欢! 年终总结:2023 年的一些回顾和 2024 年的一些小规划 千元预算组装入门 NAS 设备 分享 NAS 的硬件基础知识 我写了一本书《前端工程化:基于 Vue.js 3.0 的设计与实践》 想分享一下它背后的故事 Git的选择性合并操作笔记:合并某个版本或某个提交 年终总结:2022 年的一些回顾和 2023 年的一些小规划 知乎收藏夹助手:自动化将专栏的文章添加到收藏夹 用Vite更简单的解决Vue3项目的预渲染问题 Pinia怎么用?Vue3全局状态的管理工具Pinia教程 每天吃什么?上班带什么饭?程序员教你做菜啦!
干净的 TypeScript 项目在编译时报错 Cannot find module 'undici-types' 的原因和解决
chengpeiquan · 2024-04-06 · via 程沛权 - 养了三只猫

很久前配合 《前端工程化:基于 Vue.js 3.0 的设计与实践》 一书在 TypeScript 章节里讲解的内容,提供了一个很干净的 demo (见 hello-node ),这里的 “干净” 是指除了必要的基础技术栈外,没有过多的第三方依赖,一直运行良好。

当然在教程里还是主动引导读者自己从零开始创建这个 Hello 项目,这也带来了这个假期遇到的一个读者反馈的问题。

事情起因

前几天在 GitHub Issue 的评论区,有位读者和我反馈说在运行 npm run build 时出现类似下方的报错,无法正确编译(见 #193 (comment) )。

读者反馈
读者反馈

触发错误日志

遇到反馈的问题,首先是要先复现问题,于是先把仓库里的演示项目拉下来跑了一下,依然可以正常运行,但因为 “自己的代码自己清楚” ,马上联想到一个区别,就是读者自己创建的项目,依赖可能都是最新版,而我的演示项目由于 package.json 和 package-lock.json 里的版本号已有指定,因此 node_modules 下安装好的依赖可能并不完全一样,所以在演示仓库的项目里,这个错误没有被触发。

因此我把 node_modules 和 package-lock.json 文件删除,再重新安装依赖,确实,现在演示项目也无法通过编译了,还好日志很清晰,报错是来自 node_modules/@types/node/globals.d.ts 这个文件:

分析错误日志

由于这个项目是很入门的演示项目,主要为了演示 Common JS 模块和 ES Module 模块的开发,以及一些 TypeScript 语法的入门,并没有涉及到 Node.js API 的操作,因此也没有主动去安装 @types/node 这个包。

这里顺便补充个说明: @types/node 包主要是为 TypeScript 提供 Node.js API 的类型定义,如果在项目里调用了 Node.js 的 API ,则需要显式安装它,使 TypeScript 可以识别到这些 API 。

所以 @types/node 这个包只能是第三方依赖带进来一并被安装的,为了方便排查,重新克隆了一个演示项目的原版,并通过 npm list @types/node 查看可以正常 build 时的依赖版本号,以及是哪个包引入的这个依赖。

此时正常 build@types/node 版本号是 18.11.0 ,是从 ts-node 引入的。

同样的命令在有问题的项目下运行,得到不同的版本号 20.12.5

查看项目 node_modules/ts-node 目录下的 package.json 文件,看到 ts-node@types/node 的依赖版本号是设置为 * 号,也就是通配符(下面是关键信息的列举,非全部)。

通配符版本号是指允许任何版本的依赖项,会安装最新可用版本,这也是为什么删除了 node_modules 目录和 package-lock.json 文件后,重新安装依赖后版本变化这么大的原因。

关于这个 undici-types 依赖,查看了 @types/node 的 package.json 文件,确实在后面的版本里引入其作为 dependencies 依赖,而之前的版本并没有,在 GitHub 溜达了一圈,原因可能来自 Node.js Undici 的这个 issue )。

解决问题

原因查明,解决方案就好办了,这里提供两个有效的解决方案。

使用 skipLibCheck 选项

由于 demo 的报错主要来自第三方库的代码检查( TypeScript 默认会检查所有代码),在实际的项目开发中为了节省编译时间和跳过源码之外的问题报错,通常会启用 skipLibCheck 选项通知 TypeScript 跳过这些依赖库的类型检查(扩展名为 .d.ts 的文件),从而只检查开发者编写的源代码。

这也是为什么写了那么久的 TypeScript 从来没有遇到这种问题的原因,因为在实际项目里一直都是跳过对第三方库的检查啊哈哈哈。

选择这个方案的话,如果是走 CLI 选项编译,可以在命令里添加一个 --skipLibCheck 选项:

如果是通过 tsconfig.json 配置编译选项,则是添加在 compilerOptions 里:

关于 skipLibCheck 选项 的更多说明可以在 TypeScript 官网文档上查阅。

添加 moduleResolution

除了 skipLibCheck ,还有一个解决方案,还记得错误日志吗?在错误日志里给出了两个解决方案的建议:

由于这是一个第三方库的报错,因此 paths 方案不适用(该方案适合对源码目录下的文件配置 Alias 别名)。

因此可以通过另外一个建议,添加 --moduleResolution 选项。

也可以成功解决编译问题,同理,也可以在 tsconfig.json 里配置该选项:

关于 moduleResolution 选项 的更多说明可以在 TypeScript 官网文档上查阅。