tsconfig.app.json 和 tsconfig.json
约 3787 字大约 13 分钟
2025-11-14
在 TypeScript 项目(尤其 Vue/React 等工程化项目)中,tsconfig.json 和 tsconfig.app.json 是 “主配置 + 子配置” 的关系,核心是为了区分「整个项目的全局配置」和「应用代码(App)的专属配置」,避免配置冗余且精准控制编译范围。
继承与扩展
tsconfig.app.json 是 针对应用代码的 “子配置”,它会通过 extends 字段直接继承 tsconfig.json 的所有配置,再根据应用场景覆盖或补充特定规则。
可以理解为:
tsconfig.app.json = tsconfig.json(基础配置) + 应用专属配置(覆盖/新增)关键区别(表格对比)
| 维度 | tsconfig.json | tsconfig.app.json |
|---|---|---|
| 定位 | 项目根目录的「全局主配置」 | 应用代码的「专属子配置」 |
| 作用范围 | 整个项目(包括 App 代码、测试代码、工具脚本等) | 仅应用业务代码(如 src/ 目录) |
| 继承关系 | 无父配置,是所有子配置的 “基准” | 必须通过 extends: "./tsconfig.json" 继承主配置 |
| 核心用途 | 定义项目通用规则(如 TypeScript 版本、模块系统、全局类型) | 过滤非应用代码、定制应用编译规则(如输出目录、编译目标文件) |
| 常见配置项 | compilerOptions.target(全局 TS 目标版本)、compilerOptions.module(模块系统)、typeRoots(类型声明目录) | include(仅包含 src/**/*)、exclude(排除 node_modules/ 测试文件)、覆盖 outDir(应用输出目录) |
| 是否必须 | 是(TypeScript 项目的核心配置文件) | 否(简单项目可只用 tsconfig.json;工程化项目推荐拆分) |
以 React 项目为例:
tsconfig.app.json(应用子配置)
tsconfig.app.json 就是专门给前端项目 src 目录下的业务源代码(比如 React 组件、逻辑脚本等)提供的 TypeScript 配置,负责业务代码的类型检查、语法适配等核心需求。
{
"compilerOptions": {
// 1. 类型构建信息缓存文件路径
// 作用:TypeScript 会将编译过程中的类型检查、模块依赖等信息写入该文件
// 优势:下次编译时直接复用缓存,大幅提升二次编译速度(尤其大型项目)
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
// 2. 目标 JS 版本(编译后输出的 JS 语法版本)
// ES2022 是较新的稳定版本,支持类字段、顶层 await 等常用特性,兼顾兼容性和功能
"target": "ES2022",
// 3. 类字段使用 defineProperty 定义(而非直接赋值)
// 作用:遵循 ES 标准,确保类字段的可见性(如 public/private)和访问器行为符合预期
// 注意:配合 React 类组件或自定义类时,避免字段赋值行为不一致
"useDefineForClassFields": true,
// 4. 项目可用的全局库类型(告知 TS 代码中可使用哪些全局 API)
// ES2022:提供 ES2022 标准的全局类型(如 Array.prototype.at)
// DOM:提供浏览器 DOM API 类型(如 window、document)
// DOM.Iterable:提供 DOM 可迭代对象类型(如 NodeList 的 for...of 遍历)
"lib": ["ES2022", "DOM", "DOM.Iterable"],
// 5. 模块系统类型(代码中使用的模块规范)
// ESNext:支持最新的 ES 模块特性(如 import.meta、动态导入),适配 Vite 的 ES 模块优先策略
"module": "ESNext",
// 6. 额外引入的类型声明文件(全局可用)
// vite/client:提供 Vite 专属的类型支持(如 import.meta.env、import.meta.glob 等 Vite 全局 API 类型)
"types": ["vite/client"],
// 7. 跳过第三方库的类型检查
// 原因:第三方库(如 react、lodash)的类型声明通常已完善,跳过可大幅提升编译速度
// 避免:因第三方库类型冲突导致的编译报错(不影响业务代码类型检查)
"skipLibCheck": true,
/* Bundler mode(打包工具模式,适配 Vite 等现代化打包工具) */
// 8. 模块解析方式(告知 TS 如何查找导入的模块)
// bundler:专门为打包工具(Vite、Webpack)设计的解析逻辑,支持:
// - 裸模块导入(如 import React from 'react')
// - 导入 TS 扩展名文件(配合 allowImportingTsExtensions)
// - 打包工具的特殊解析规则(如 Vite 的路径别名、条件导出)
"moduleResolution": "bundler",
// 9. 允许导入时带 .ts/.tsx 扩展名
// 示例:import { Button } from './Button.tsx'(无需写成 ./Button)
// 适配 Vite 的原生 ES 模块解析逻辑,避免手动配置路径别名时的后缀问题
"allowImportingTsExtensions": true,
// 10. 严格保留模块语法(不自动转换模块类型)
// 作用:禁止 TS 自动将 ES 模块转为 CommonJS(如 require/module.exports)
// 适配 Vite:确保代码以 ES 模块形式被打包,避免模块系统冲突
"verbatimModuleSyntax": true,
// 11. 强制将所有文件视为模块(即使没有导入/导出)
// 避免:无导入/导出的文件被 TS 视为全局脚本,导致变量污染或类型冲突
"moduleDetection": "force",
// 12. 不生成编译产物(.js/.d.ts 等文件)
// 核心原因:Vite 会单独处理代码编译和打包,TS 仅负责类型检查(不参与实际构建)
// 优势:减少冗余文件,提升开发效率
"noEmit": true,
// 13. JSX 语法处理方式(适配 React 17+ 的新 JSX 转换)
// react-jsx:使用 React 自带的 jsx 运行时(无需手动导入 import React from 'react')
// 替代旧版 "jsx": "react",减少代码体积,支持 JSX 隔离编译
"jsx": "react-jsx",
/* Linting(严格类型检查,提前规避代码问题) */
// 14. 开启所有严格类型检查规则(核心开关)
// 包含:noImplicitAny、strictNullChecks、strictFunctionTypes 等关键规则
// 目的:强制规范代码,避免隐式类型错误(如 null/undefined 调用、任意类型 any 滥用)
"strict": true,
// 15. 禁止未使用的局部变量
// 作用:清理冗余代码,避免变量声明后未使用导致的代码臃肿
"noUnusedLocals": true,
// 16. 禁止未使用的函数参数
// 作用:优化函数定义,避免参数冗余(如函数声明了参数但未在函数体内使用)
"noUnusedParameters": true,
// 17. 仅检查可擦除的语法(不影响运行时的类型语法)
// 作用:只验证 TypeScript 语法正确性(如类型注解、接口定义),不干涉 JS 运行时逻辑
// 适配 Vite:确保类型语法被正确解析,同时不影响 Vite 的构建流程
"erasableSyntaxOnly": true,
// 18. 禁止 switch 语句中的穿透情况(case 未加 break/return 导致的逻辑错误)
// 示例:case 1: console.log(1); // 无 break,会穿透到 case 2,触发报错
// 作用:避免逻辑漏洞,强制规范 switch 语句写法
"noFallthroughCasesInSwitch": true,
// 19. 禁止导入有未检查副作用的模块
// 作用:避免导入仅执行副作用(如修改全局变量、执行 DOM 操作)但未声明的模块
// 优势:提升代码可维护性,明确副作用来源
"noUncheckedSideEffectImports": true
},
// 20. 编译/类型检查的文件范围:仅包含 src 目录下的所有文件
// 目的:精准定位应用业务代码,排除测试文件、工具脚本等(避免无关文件类型检查)
"include": ["src"]
}tsconfig.node.json(脚手架运行的配置)
{
"compilerOptions": {
// 1. Node 脚本专属的类型构建信息缓存文件
// 作用:和 tsconfig.app.json 分开缓存,避免应用代码和 Node 脚本的编译缓存冲突
// 优势:单独优化 Node 脚本的二次编译速度(如修改 vite.config.ts 后快速重新类型检查)
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
// 2. 目标 JS 版本(适配 Node 环境)
// ES2023:Node.js 18+ 已完全支持 ES2023 特性(如 Array.prototype.findLast、Hashbang 支持)
// 差异:比 tsconfig.app.json 的 ES2022 更高,因为 Node 环境的兼容性比浏览器更可控
"target": "ES2023",
// 3. 项目可用的全局库类型(仅 Node 核心 API 类型)
// 仅包含 ES2023:无需 DOM 相关类型(Node 环境无浏览器 DOM API)
// 差异:和 tsconfig.app.json 相比,移除了 "DOM" 和 "DOM.Iterable",避免类型冗余
"lib": ["ES2023"],
// 4. 模块系统类型(适配 Node 环境的 ES 模块)
// ESNext:支持 Node 最新的 ES 模块特性(如 import.meta.url、顶层 await)
// 一致:和 tsconfig.app.json 保持一致,适配 Vite 的 ES 模块优先策略
"module": "ESNext",
// 5. 额外引入的类型声明文件(Node 环境专属)
// "node":提供 Node.js 核心 API 的类型支持(如 fs、path、http 模块,process 全局对象)
// 差异:替代 tsconfig.app.json 的 "vite/client",因为 Node 脚本不需要浏览器/Vite 客户端类型
"types": ["node"],
// 6. 跳过第三方库的类型检查
// 作用:和 tsconfig.app.json 一致,跳过 node_modules 中第三方库(如 vite、rollup)的类型检查
// 优势:提升 Node 脚本的类型检查速度,避免第三方库类型冲突
"skipLibCheck": true,
/* Bundler mode(打包工具模式,适配 Vite 配置的构建逻辑) */
// 7. 模块解析方式(适配打包工具 + Node 环境)
// "bundler":支持 Vite 配置中使用的路径别名、条件导出,同时兼容 Node 模块解析规则
// 一致:和 tsconfig.app.json 保持一致,确保模块查找逻辑统一
"moduleResolution": "bundler",
// 8. 允许导入时带 .ts 扩展名
// 示例:在 vite.config.ts 中可直接 import { resolve } from './utils.ts'
// 一致:和 tsconfig.app.json 保持一致,适配 Vite 的原生 ES 模块解析
"allowImportingTsExtensions": true,
// 9. 严格保留模块语法(不转换为 CommonJS)
// 作用:确保 Vite 配置文件以 ES 模块形式被 Node 识别(需配合 package.json 的 "type": "module")
// 一致:和 tsconfig.app.json 保持一致,避免模块系统冲突
"verbatimModuleSyntax": true,
// 10. 强制将所有文件视为模块
// 作用:避免 vite.config.ts 因无显式导入/导出被视为全局脚本,导致变量污染
// 一致:和 tsconfig.app.json 保持一致,规范文件模块行为
"moduleDetection": "force",
// 11. 不生成编译产物
// 核心原因:Vite 配置文件(vite.config.ts)由 Vite 自身通过 esbuild 转译执行,TS 仅负责类型检查
// 一致:和 tsconfig.app.json 保持一致,避免生成冗余的 .js 文件
"noEmit": true,
/* Linting(严格类型检查,规范 Node 脚本代码) */
// 12. 开启所有严格类型检查规则
// 作用:和 tsconfig.app.json 一致,强制 Node 脚本(如 vite.config.ts)的类型规范
// 避免:如 null/undefined 调用、any 类型滥用等问题
"strict": true,
// 13. 禁止未使用的局部变量
// 作用:清理 vite.config.ts 中的冗余变量,保持配置文件简洁
"noUnusedLocals": true,
// 14. 禁止未使用的函数参数
// 作用:优化 Vite 配置中的插件函数、钩子函数,避免参数冗余
"noUnusedParameters": true,
// 15. 仅检查可擦除的语法
// 作用:只验证 TypeScript 类型语法(如接口、类型注解),不干涉 Node 脚本的运行时逻辑
"erasableSyntaxOnly": true,
// 16. 禁止 switch 语句穿透
// 作用:规范 Vite 配置中可能的 switch 逻辑(如环境变量判断),避免逻辑漏洞
"noFallthroughCasesInSwitch": true,
// 17. 禁止导入有未检查副作用的模块
// 作用:避免在 Vite 配置中导入未知副作用的模块(如修改 Node 全局变量的脚本)
// 优势:提升配置文件的可维护性,明确副作用来源
"noUncheckedSideEffectImports": true
},
// 18. 编译/类型检查的文件范围:仅包含 Vite 配置文件
// 核心目的:精准定位 Node 环境脚本(vite.config.ts 是项目中最主要的 Node 脚本)
// 差异:和 tsconfig.app.json 的 "include": ["src"] 区分,避免应用代码和 Node 脚本的类型混淆
"include": ["vite.config.ts"]
}前端项目(如 Vite + React)的运行,需要依赖 Node 环境的工具脚本(比如 vite.config.ts)来启动开发服务器、处理打包构建。tsconfig.node.json 就是专门给这些「工具脚本」做类型检查的配置,让脚手架相关的脚本能在 Node 环境中正确运行,同时和前端业务代码的类型环境隔离开。
前端工程化的核心是 “用 Node 工具链支撑前端开发”,比如:
- 你执行
npm run dev时,实际是 Node 运行了 Vite 的 CLI 工具; - Vite 的 CLI 会读取
vite.config.ts(Node 脚本),根据配置启动开发服务器、处理模块打包、解析别名等; vite.config.ts里会用到 Node 环境的 API(如path.resolve、process.env)和 Vite 的 Node 端 API(如defineConfig、插件配置),这些都需要 Node 相关的类型支持。
tsconfig.node.json 的核心作用就是:
- 给
vite.config.ts这类「Node 工具脚本」提供类型提示(比如node类型让 TS 认识process、fs等); - 避免 Node 环境的类型(如
global、module)和前端浏览器环境的类型(如window、DOM)冲突; - 让 TypeScript 只针对这些工具脚本做精准的类型检查,不干扰前端业务代码。
tsconfig.json(主配置)
{
// 1. 明确指定当前配置文件直接包含的文件(空数组表示无直接包含的文件)
// 原因:当前主配置仅用于聚合子配置,不直接处理文件编译
"files": [],
// 2. 项目引用(TypeScript 3.0+ 特性,用于多配置拆分)
// 作用:将项目拆分为多个独立的子项目(应用代码、Node 脚本),支持:
// - 并行编译(提升构建速度)
// - 子项目类型隔离(避免应用代码和 Node 代码类型冲突)
// - 配置复用(无需重复写通用规则)
"references": [
// 引用应用代码配置(tsconfig.app.json:处理 src 目录下的 React 业务代码)
{ "path": "./tsconfig.app.json" },
// 引用 Node 脚本配置(tsconfig.node.json:处理 Vite 配置、Node 工具脚本等)
{ "path": "./tsconfig.node.json" }
]
}files 是 TS 配置中「明确指定要编译 / 类型检查的单个文件列表」,仅支持具体文件路径(如 ["src/index.ts"]),不支持通配符。
配置中 files: [](空数组),意思是「当前配置文件不直接处理任何文件」,完全靠 references 关联子配置 —— 这正是 Vite 项目的典型用法,主配置只做聚合,不直接参与文件处理。
核心场景:只需要给少数几个关键文件做 TS 配置时用(比如简单项目只有 1-2 个 TS 文件),但工程化项目(如 Vite/React)更常用 include(支持通配符)或 references(聚合子配置),所以 files 用得少。
tsconfig.json 是项目根目录的「主配置入口」,核心作用是聚合 tsconfig.app.json/tsconfig.node.json 等子配置(通过 references 关联),也可存放所有子配置共用的全局性 TypeScript 规则。
tsconfig.json 用 references 聚合子配置,自身不直接处理文件(files 为空),是 “纯聚合型” 主配置;
简单项目中,也可以在 tsconfig.json 里直接写全局规则(如 strict: true、target: ES2022),让子配置通过 extends 继承,避免重复配置 —— 本质还是 “全局基准 + 子配置差异化” 的思路。
拆分的优势
区分场景:应用代码(App)和测试代码(Test)、工具脚本(Script)的编译需求不同(如测试代码需要 jest 类型,应用代码不需要),拆分后可分别配置。
提升编译速度:tsconfig.app.json 仅包含 src/ 目录,避免编译无关文件(如测试、文档),减少 TypeScript 类型检查和编译的范围。
配置复用:主配置定义通用规则,子配置只关注差异项,避免重复写配置(如 strict: true 不需要在每个子配置中重复声明)。
工程化规范:大型项目中,通过 tsconfig.app.json、tsconfig.spec.json(测试)、tsconfig.node.json(Node 脚本)拆分,让配置更清晰,团队协作更规范。