TypeScript编译器常用命令核心配置选项两部分。

常用命令速查

这些是你日常开发中最常敲的命令:

命令 含义与用途
tsc 默认构建。自动寻找当前目录下的 tsconfig.json 文件并编译整个项目。
tsc -w 监听模式。编译后会保持运行,一旦文件有改动,自动重新编译(开发时很有用)。
tsc --init 初始化。在当前目录生成一个包含推荐设置的 tsconfig.json 文件。
tsc -p <路径> 指定项目配置-p / --project 指向某份 tsconfig.json 文件,或含有 tsconfig.json 的目录;编译范围由该配置里的 include / files 等决定,不是随便传一个源码目录。例如:tsc -p tsconfig.app.jsontsc -p packages/foo(该目录下需有 tsconfig.json)。
tsc -b 构建模式。专为 monorepo/多项目场景设计,会按依赖顺序构建(先编译被依赖的,再编译依赖它的),并生成缓存加速下次构建。普通项目用 -b 和直接用 tsc 区别不大。
tsc --noEmit 仅检查。不写任何产物:既不生成 .js,也不生成 .d.ts(终端里仍可能打印类型错误/告警)。若只要类型声明、不要 JS,用 tsc --emitDeclarationOnly(并开 declaration: true,或 -d)。
tsc --showConfig 查看配置。打印最终解析后的配置信息,而不进行构建(用于排查配置问题)。
tsc -v 查看版本。显示当前 TypeScript 的版本号。

tsconfigfilesinclude 会冲突吗?

不冲突,是优先级关系:

配置 作用
files 显式列出根文件;若写了此项,官方语义下 include / exclude 会被忽略
include 用通配符(如 src/**/*)决定进哪些文件;未写 files 时才按它与 exclude 生效。
exclude include 结果里再排除;若只用了 files,一般不参与。

实务上:要么只用 include(+ 可选 exclude),要么只用 files 做白名单,避免混写后误以为 include 仍在生效。

核心配置选项

这些选项通常写在 tsconfig.json 中,或者作为参数跟在命令后面:

语言环境设置
  • --target (或 -t): 指定编译后的 JavaScript 版本。

    • 常见值:es5, es6 (或 es2015), esnext

    含义:指定编译后的 JavaScript 代码要兼容哪种 ES 版本。例如设为 es5,会把 const/let 转成 var,箭头函数转成普通函数。设为 es6 则保留新语法。

    与 Babel/SWC/esbuild 的差异:tsc --target 属于 TypeScript 编译阶段的“语言级降级”(按目标 ES 版本转换语法)。Babel/SWC/esbuild 通常在工程构建链路中负责面向目标运行环境的最终兼容转换,并可通过插件做更细粒度处理。

    • 一句话区分:tsc 关注“TS 代码如何编译成目标 JS 语法”;Babel/SWC/esbuild 关注“最终产物如何兼容目标环境(不同浏览器兼容性等)并接入构建能力”。
  • --module (或 -m): 指定使用哪种模块系统。

    • 常见值:commonjs, esnext, node16
    • 作用:决定 TypeScript 输出后的 JS 采用哪种模块组织方式(例如保留 ESM,或转换为 CommonJS 风格)。
    • 常见场景:
      • commonjs:偏传统 Node.js 生态,输出更接近 require/module.exports 语义。
      • esnext:前端工程常用,保留 import/export 交给 Vite/Rollup/Webpack 做后续处理。
      • node16:按 Node 16+ 的模块解析规则工作,适合现代 Node 服务端项目。
    • 选择建议:前端(Vite)通常用 esnext;Node 后端按运行环境选 node16commonjs
  • --lib: 指定要包含的库文件(定义全局变量如 window, document 等)。

    • 常见值:dom, es2015, esnext
    • 作用:决定 TypeScript 在类型检查时“认为你的运行环境有哪些内置 API”。
    • 关键区别:
      • esnext:JavaScript 标准库类型(Promise、新数组方法等),不包含浏览器对象。
      • dom:浏览器环境 API 类型(windowdocumentHTMLElement 等)。
      • dom.iterable:给部分 DOM 集合补充可迭代类型(可 for...ofArray.from)。
    • 容易混淆的点:esnext 不包含 dom,它们是可组合关系,不是包含关系。
    • 选择建议:
      • 前端项目常见:["ESNext", "DOM", "DOM.Iterable"]
      • Node 项目常见:["ESNext"](再结合 @types/node)。
输出与文件处理
  • --outDir: 指定输出文件的目录(例如 distbuild)。
  • --declaration (或 -d): 是否生成 .d.ts 类型声明文件(写库的时候必开)。
  • --sourceMap: 是否生成 .map 文件(用于调试,让你能在浏览器里调试 TS 源码)。
  • --jsx: 如何处理 JSX 语法。
    • 常见值:react (生成 React.createElement), react-jsx (React 17+ 新语法), preserve (保留不动,交给 Vite/Rollup 处理)。
    • Vite + React 项目常见做法:使用 react-jsx,再由 Vite 插件链(Babel/SWC/esbuild)完成后续构建转换。
    • 为什么“后面有 Babel/SWC 转 JSX”仍常保留 react-jsx
      • TypeScript 即使 noEmit 不产出 JS,也要做类型检查;jsx 选项会影响 TS 对 JSX 的类型语义理解。
      • Babel/SWC/esbuild 对 JSX 的处理属于构建转换阶段,与 TS 的类型语义检查不是同一层。
      • 可记忆为:TS 的 jsx 负责“按哪种 React JSX 语义做检查”;Babel/SWC 的 JSX 转换负责“把源码转成可运行代码”。
严格程度与兼容性
  • --strict: 开启所有严格检查

    • 建议:生产项目务必开启,它能帮你避免很多 undefined is not an object 的运行时错误。
  • --allowJs: 允许编译 JavaScript 文件(即允许项目中混用 .js.ts)。

  • --esModuleInterop: 让 import X from 'xxx' 语法能正常工作于 CommonJS 模块。

    背景:npm 上很多老库(如 lodash、moment)是用 module.exports = xxx(即 CommonJS)写的,它们没有"默认导出"的概念。而你写的 import _ from 'lodash' 需要默认导出。没有这个参数时,导入的 _ 可能是空的。加上它之后,TypeScript 会自动处理这个差异。

📌 总结建议

如果你刚开始配置项目,最核心的命令通常是:

  1. tsc --init 生成配置文件。
  2. 在配置文件中开启 "strict": true"esModuleInterop": true
  3. 开发时使用 tsc -w 或配合构建工具(如 Vite/Webpack)自动运行。

JavaScript 转译工具对比

一句话总览

  • Babel / SWC / esbuild 主要解决“代码如何被转换”;
  • Vite / Rollup / Webpack 主要解决“工程如何被构建与输出”。

工具概览

工具 开发公司 语言 速度 用途
Babel 社区开源 JavaScript 慢(基准) 转译 JS/TS/JSX,插件生态最全
SWC Vercel/SWC团队 Rust 快 ~20x Babel 替代品,兼容大部分插件
esbuild Figma (Evan Wallace) Go 最快 ~100x 打包/压缩/依赖预构建

工具定位(先看这个)

工具 核心定位 在 Vite 中的常见角色
Babel 转译能力最灵活,插件生态最强 通过 @vitejs/plugin-react 参与 JSX/TSX 转译与插件扩展
SWC Rust 实现的高性能转译器 通过 @vitejs/plugin-react-swc 承担 React/TS 转译
esbuild 超快的转换/打包/压缩工具 开发时做依赖预构建;生产常用于 JS 压缩

说明:三者互为竞争关系,目标一致(转译 JS),但速度、定位、生态不同。

与 Vite / Rollup / Webpack 的关系

  • Vite / Rollup / Webpack 是工程级构建器(模块图、代码拆分、资源处理、输出产物)。
  • Babel / SWC / esbuild 常作为其内部环节(转译、压缩、预构建等)被调用。

Vite 流程拆解(最容易混淆)

阶段 发生在什么命令 主要做什么 常见工具
依赖预构建 vite dev 预处理 node_modules,提升冷启动和请求效率 esbuild
HMR vite dev 模块热更新与状态保留 Vite HMR 机制 + React Refresh
应用源码转译 vite devvite build 处理业务源码中的 TS/JSX/语法转换 Babel / SWC / esbuild(取决于插件与配置)
最终打包输出 vite build 产出 dist、代码拆分、Tree-shaking Rollup(主)+ esbuild(常用于压缩)

什么是预构建(Pre-bundling)

  • 预构建主要针对 依赖node_modules),不是业务源码。
  • 核心目标是把依赖整理成开发服务器更高效可用的形态,并减少首次加载成本。
  • 这一步在 Vite 中默认由 esbuild 承担。

选型建议

  • 需要复杂插件生态、定制转换规则:优先 Babel
  • 追求高性能且需求相对标准:优先 SWCesbuild
  • Vite 项目默认先用官方推荐配置,只有在性能或插件诉求明确时再切换方案。

常见问题

Q: @babel/preset-typescripttsc 的区别?

  • tsc:类型检查 +编译输出(可选)。
  • @babel/preset-typescript:只移除类型并转译,不做类型检查。
    • 简单理解:TypeScript 类型注解(如 name: string、返回值 : string)主要服务于开发期提示与校验;转译到 JavaScript 时会被移除,运行时并不保留这些类型信息。
    • 示例:
      // TypeScript(带类型注解)
      function greet(name: string): string {
        return name.toUpperCase()
      }
      
      // 转译后 JavaScript(类型被移除)
      function greet(name) {
        return name.toUpperCase()
      }
      

Q: 已经有 tsc,为什么还会用 Babel/SWC?

  • 常见分工是:tsc --noEmit 负责类型检查,Babel/SWC/esbuild 负责构建链路内的代码转换。
  • 补充:tsc --noEmit 很常见,但这不等于“必须使用 @babel/preset-typescript”。
    • 只有当 Babel 直接处理 .ts/.tsx 源码 时,通常才需要 @babel/preset-typescript
    • 如果转译由 esbuild/SWC/Vite 内置链路 完成,通常不需要该 preset。
    • 可以分两种模式理解:
      • 模式 A:先 tsc 产出 JS,再让 Babel 处理 JS。这种情况下通常不需要 @babel/preset-typescript(因为 Babel 已经看不到 TS 类型语法)。
      • 模式 B(推荐)tsc 只做类型检查(--noEmit),Babel 直接处理 .ts/.tsx 源码。这时通常需要 @babel/preset-typescript,否则 Babel 默认无法识别类型注解。
TypeScript + Vite 推荐实践
  • 开发:vite(快速启动与 HMR)。
  • 类型检查:tsc --noEmit(只检查,不产出 JS)。
  • 生产构建:vite build(打包与产物输出)。

可参考的脚本拆分:

{
  "scripts": {
    "dev": "vite",
    "typecheck": "tsc --noEmit",
    "build": "vite build",
    "build:check": "tsc --noEmit && vite build"
  }
}

Q: Vite 内置的是 esbuild 还是 SWC?

  • Vite 内置 esbuild(依赖预构建、压缩等)。
  • SWC 需要额外安装对应插件(如 @vitejs/plugin-react-swc)。

Q: 为什么 tsc 没有输出?(Project References 问题排查)

执行 tsc 时没有任何类型错误输出,可能是因为项目使用了 Project References

典型场景:根目录 tsconfig.json 使用了以下模式:

{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

问题分析:

  • "files": [] 明确声明"当前配置不包含任何源文件"
  • "references" 声明依赖的子项目
  • 直接运行 tsc --noEmit 时,TypeScript 加载根配置,发现 files 为空就静默退出了

解决方案:

命令 说明
tsc -b 构建所有引用项目(推荐,package.json 的 build 脚本常用)
tsc --noEmit -p tsconfig.app.json 指定具体配置文件
tsc -b tsconfig.app.json 只构建 app 子项目

Q: @rollup/plugin-typescript@rollup/plugin-babel + @babel/preset-typescript 能力对比?

能力 @rollup/plugin-typescript @rollup/plugin-babel + @babel/preset-typescript
TS → JS 转换
类型检查
生成 .d.ts
速度 较慢(tsc) 快(Babel)

关系总结:

  • @rollup/plugin-babel桥梁,把 Babel 接入 Rollup
  • @babel/preset-typescriptBabel 的 TS 插件,移除 TS 类型注解
  • 两者是上下游关系:plugin 调用 preset

Q: Rolldown 是什么?现在成熟吗?
Rolldown 是一个用 Rust 编写的高性能 JavaScript/TypeScript 打包工具(Bundler)。
简单来说,你可以把它看作是 Rollup 的 Rust 版本。它的核心目标是提供与 Rollup 完全兼容的 API 和插件接口,但利用 Rust 的性能优势,实现比现有 JavaScript 打包工具(如 Webpack、Rollup、甚至 Vite 的默认构建)快得多的构建速度。但目前并不成熟。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐