本节目标:把「装环境」这件小事讲透。读完后,你的机器上会同时具备 Node.js 运行时、npm 包管理器、项目本地安装的 TypeScript 编译器,以及一个能实时提示类型错误的编辑器。更重要的是,你会知道每一步为什么这么做,以及出问题时该往哪儿看。
2.1 安装 Node.js、TS 与编辑器配置
很多初学者把安装环境当成一段「照抄命令」的仪式:复制、粘贴、回车,跑通就完事。但环境是后面所有章节的地基——第 3 章起我们要反复运行 npx tsc,第 15 章要跑测试,第 16 章要配置构建产物。如果地基是随手拼起来的,后面每一个报错你都会怀疑是语言本身的问题。
所以这一节我们按「运行时 → 包管理器 → 编译器 → 编辑器」的顺序,一层层装上去,并且每一层都验证一次。
2.1.1 为什么学 TypeScript 先要装 Node.js
一个常见的疑问是:TypeScript 最终要变成 JavaScript 跑在浏览器里,那为什么不能只装个编辑器就完事?
答案在于编译器本身也是 JavaScript 程序。tsc(TypeScript Compiler)不是操作系统自带的命令,它是一份用 TypeScript 写、编译成 JavaScript 的代码,需要有人来执行它。浏览器不会替你在命令行执行脚本,于是就需要一个能跑 JavaScript 的本地运行时——这就是 Node.js。
顺着这条链,三个工具的关系就清楚了:
| 工具 | 角色 | 由谁提供 | 本章会用到它做什么 |
|---|---|---|---|
| Node.js | JavaScript 运行时 | Node.js 官方 | 执行 tsc、执行编译后的 .js |
| npm | 包管理器(随 Node 一起装) | Node.js 官方 | 下载 typescript 等依赖、跑 npm scripts |
| npx | 包执行器(随 npm 一起装) | npm 团队 | 直接运行本地依赖里的命令行工具 |
| typescript | 编译器 + 语言服务 | npm 上的 typescript 包 | 把 .ts 转成 .js,并给出类型报错 |
换句话说,Node.js 是「地基」,npm 是「运输车」,typescript 是「加工设备」,编辑器则是「操作台」。缺了地基,后面三样都无处安放。
值得一提的是,Node.js 并不是唯一的 JavaScript 运行时。Bun 和 Deno 也能执行 TypeScript,并且开箱即用;它们的定位差异可以延伸阅读 Node.js vs Bun vs Deno 三大 JavaScript Runtime 架构深度对比 。但本书面向零基础读者,统一以 Node.js + npm 为主线,因为它是生态里兼容性最好、遇到问题最容易搜到答案的组合。
2.1.2 三种安装 Node.js 的方式
Node.js 的安装方式不止一种,选错方式不会立刻出问题,但会在半年后给你带来「同事能跑我不能跑」的困扰。先看对比:
| 方式 | 优点 | 缺点 | 适合谁 |
|---|---|---|---|
| 官方安装包(.pkg / .msi) | 图形界面,下一步到底 | 换版本要卸载重装,难以多版本共存 | 完全零基础、只做一门课 |
| 版本管理器(nvm / fnm / n) | 一条命令切换版本,多项目互不干扰 | 多一个概念要学,Windows 需用 nvm-windows | 本书推荐,尤其是要维护多个项目的人 |
| 系统包管理器(Homebrew / apt) | 与系统其他软件统一管理 | 版本常常滞后,权限问题较多 | 已经重度使用 Homebrew 的 macOS 用户 |
为什么推荐版本管理器?因为 Node 的大版本升级会带来不兼容变更。假设你的老项目必须跑在 Node 18 上,而新项目要求 Node 22,全局安装包只能二选一,版本管理器却可以随时切换。
以 nvm 为例,安装后典型用法如下:
# 查看所有可安装的 LTS 版本
nvm ls-remote --lts
# 安装当前最新的 LTS(长期支持)版本
nvm install --lts
# 查看本地已安装的版本
nvm ls
# 把默认版本设为 LTS,避免每次开新终端都要手动切
nvm alias default lts/*
# 在某个项目里临时切到 18
nvm use 18
选择版本时有一个实用原则:生产项目永远优先选 LTS(Long Term Support)。奇数版本(如 21、23)是尝鲜版,生命周期短,不适合作为长期开发环境。本书示例代码在 Node 20 LTS 及以上版本均可运行。
如果你想了解 Node.js 这些年的版本演进脉络与选型逻辑,可以延伸阅读 Node.js 兴发与未来 。
2.1.3 验证安装:node、npm、npx 三个命令
安装完不要急着往下走,先验证。这一步只要 10 秒,却能省掉后面半小时的困惑。
node -v
# 期望输出形如:v20.11.1
npm -v
# 期望输出形如:10.2.4
npx -v
# 期望输出形如:10.2.4
三个命令分别对应:
node -v:确认运行时可用,同时确认版本号。npm -v:确认包管理器可用。npm 的版本与 Node 版本是绑定的,所以它一般不会单独出问题。npx -v:确认包执行器可用。npm 5.2 之后npx随 npm 一起提供,如果你这里报错,说明 npm 太旧了。
再补一条更有信息量的命令:
node -p "process.versions"
# 输出一个对象,包含 node、v8、openssl 等各组件的精确版本
# { node: '20.11.1', v8: '11.3.244.8-node.17', openssl: '3.0.13', ... }
process.versions 能一次性告诉你 V8 引擎的版本。当你需要判断「某个新语法能不能用」时,查 V8 版本比查 Node 版本更准确,因为语法支持是由引擎决定的。
如果某个命令返回 command not found 或「不是内部或外部命令」,先别怀疑安装包损坏,99% 的情况是 PATH 没生效。见 2.1.6 节。
2.1.4 安装 TypeScript:本地依赖,而不是全局命令
现在到了关键决策点。你会在网上看到两种写法:
# 写法 A:全局安装(不推荐)
npm install -g typescript
# 写法 B:项目本地安装(推荐)
npm init -y
npm install --save-dev --save-exact typescript@5.9.3
先看写法 B 的实际效果。在空目录里执行:
mkdir ts-demo && cd ts-demo
npm init -y
npm install --save-dev --save-exact typescript@5.9.3
此时目录里会多出两个东西:package.json 里多了一条开发依赖,以及一个 node_modules/typescript 目录。
{
"name": "ts-demo",
"version": "1.0.0",
"devDependencies": {
"typescript": "5.9.3"
}
}
本章固定 5.9.3,让命令与编译输出可复现;--save-exact 把精确版本写入清单。一般项目也会用 ^5.9.3 这样的语义化版本(semver)范围,允许升级 5.x,但不跨大版本。如果你对 ^、~ 这些符号的精确含义还不熟,可以延伸阅读 semver 依赖解析
;第 11 章还会专门讨论 npm 包与类型声明。
为什么强烈建议本地安装? 三个理由:
- 版本随项目走。 全局只有一个 TypeScript 版本,而你同时维护的两个项目可能分别需要 4.9 和 5.4。全局安装时,升级一个项目的编译器就会影响另一个。
- 协作可复现。 本地依赖记录在
package.json与package-lock.json里,同事提交并使用同一份锁文件,执行npm ci后拿到相同的依赖树。全局版本则完全取决于各自机器上装了什么。 - 可以用 npx 精确调用。
npx tsc会优先使用当前项目node_modules/.bin下的tsc,而不是全局那个。
安装完成后验证本地版本:
npx tsc -v
# 固定版本后的输出:Version 5.9.3
tsc -v
# 如果没做全局安装,这条会报 command not found —— 这是正常现象
请记住这个区别:npx tsc 用本地版本,tsc 用全局版本。本章之后的所有命令都统一写 npx tsc,这样无论你的机器上有没有全局 TypeScript,结果都一致。
2.1.5 编辑器配置:让类型错误即时可见
TypeScript 的一半价值在于「写的时候就告诉你错了」,而这份能力由编辑器的语言服务提供。主流编辑器都支持,本书以 VS Code 为例。
VS Code 内置了 TypeScript 语言服务,不需要额外安装 TypeScript 插件——这一点常被误解。内置版本会用于语法高亮与基础提示;而当项目里安装了本地 typescript 依赖时,VS Code 可以使用项目版本,但需要确认已选择它,不能仅凭安装本地包就假定切换完成,步骤见 VS Code 的 TypeScript 版本选择说明
。
如果你用的是 JetBrains 系列或 Vim/Neovim,语言服务能力来自同一个 typescript 包,配置方式不同但原理一致。想了解编辑器插件如何与语言服务通信,可延伸阅读 TypeScript 语言服务与编辑器插件
。
接下来做三件小事。第一,在项目根目录建立 .vscode/settings.json:
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
"editor.tabSize": 2,
"files.eol": "\n"
}
逐项说明:
| 设置项 | 作用 | 为什么建议这样配 |
|---|---|---|
typescript.tsdk | 指定语言服务使用的 TypeScript 路径 | 提供项目版本路径;仍需选择工作区版本 |
editor.formatOnSave | 保存时自动格式化 | 团队协作中减少无意义的缩进 diff |
editor.tabSize | 缩进宽度 | 2 空格是 TS 生态的事实标准 |
files.eol | 换行符 | 统一为 LF,避免 Windows 上出现整文件 diff |
第二,建立 .vscode/extensions.json,把推荐插件写进仓库,同事打开项目时会收到提示:
{
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
第三,打开一个 .ts 文件,在命令面板执行 TypeScript: Select TypeScript Version,选择 Use Workspace Version,确认状态栏为 5.9.3;再验证类型提示。新建 hello.ts:
const message: string = "hello, typescript";
const wrong: number = "这行会立刻出现红色波浪线";
console.log(message);
把鼠标悬停在 wrong 上,你会看到编辑器提示:不能将类型“string”分配给类型“number”。如果这条提示出现了,说明语言服务已经就位,你的环境真正可用了。
2.1.6 常见坑与错误信息
以下四类问题覆盖了 90% 的安装故障,建议按顺序排查。
坑一:command not found / 「不是内部或外部命令」
现象:node -v 报 zsh: command not found: node。
原因:可执行文件所在目录没有加入 PATH。用 nvm 安装时,需要确保初始化脚本写进了 shell 配置文件:
# zsh 用户:确认 ~/.zshrc 里存在这两行
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
# 改完后重新加载
source ~/.zshrc
坑二:权限错误 EACCES: permission denied
现象:npm install -g typescript 报 EACCES。
原因:用系统级 Node 安装包时,全局目录属于 root。解决办法不是加 sudo(那会让后续所有 npm 操作都需要 sudo,后患无穷),而是改用版本管理器,或把 npm 的全局目录指到用户目录下:
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
export PATH=~/.npm-global/bin:$PATH
坑三:编辑器提示与命令行不一致
现象:编辑器里明明有红色波浪线,npx tsc 却不报错;或者反过来。
原因:编辑器用了自己内置的 TypeScript 版本,而命令行用了项目本地版本。按 2.1.5 节配置 typescript.tsdk,再执行 TypeScript: Select TypeScript Version 选择工作区版本;必要时重启 TypeScript Server。
坑四:Node 版本过低导致语法不支持
现象:运行某个新语法时报 SyntaxError: Unexpected token,但编辑器里不报错。
原因:编辑器按 TypeScript 的类型规则检查,而 Node 运行时按 V8 引擎的语法规则执行。Node 版本低,V8 就旧。用 node -p "process.versions.v8" 确认引擎版本,再对照目标语法的最低要求决定是否升级 Node。
2.1.7 环境自检清单
在进入下一节之前,逐条确认:
| 检查项 | 命令 | 通过标准 |
|---|---|---|
| Node 可用 | node -v | 输出 v20.x 或更高 |
| npm 可用 | npm -v | 输出 10.x 或更高 |
| npx 可用 | npx -v | 输出与 npm 相同版本 |
| 项目已初始化 | cat package.json | 存在 devDependencies.typescript |
| 本地 TS 可用 | npx tsc -v | 输出 Version 5.x |
| 编辑器提示生效 | 打开 hello.ts | 类型错误显示红色波浪线 |
六项全部通过,说明你的环境已经可以支撑本书后续所有示例。
小结
本节我们完成了一条完整的工具链:Node.js 提供运行时,npm 负责依赖管理,TypeScript 作为项目本地依赖被安装(而非全局命令),编辑器通过语言服务把类型错误提前暴露在编写阶段。我们也反复强调了两条原则:优先使用版本管理器以支持多项目共存,以及用 npx 调用本地工具以保证结果可复现。
环境装好之后,下一个问题自然浮出水面:npx tsc 到底做了什么?它为什么会把 .ts 变成 .js?编译器怎么知道该处理哪些文件、输出到哪里?这些问题的答案都指向同一个配置文件——tsconfig.json。下一节 2.2 tsc 与 tsconfig.json 初探
就来拆开这个文件。如果你对 TypeScript 在整个生态中的位置还没有整体印象,也可以先回看 1.3 适用场景与生态版图
。
阅读导航:上一节:1.3 适用场景与生态版图 · 下一节:2.2 tsc 与 tsconfig.json 初探 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。