第 109 章:tsconfig.json 详解
学习目标
- 掌握 tsconfig.json 的完整配置
- 理解 strict 模式与各类检查
- 学会项目引用与 monorepo 配置
- 能根据项目类型选择合适的配置模板
一、tsconfig.json 基础
1.1 初始化配置
bash
# 交互式生成
npx tsc --init
# 生成 tsconfig.json1.2 文件结构
json
{
"compilerOptions": {
// 编译选项
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"],
"files": ["src/index.ts"],
"extends": "./base.json",
"references": [
{ "path": "./packages/core" }
]
}1.3 配置继承
json
// tsconfig.base.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true
}
}
// tsconfig.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
}
}二、核心编译选项
2.1 target - 编译目标
json
{
"compilerOptions": {
"target": "ES2020" // 输出符合 ES2020 标准的 JS
}
}可选值:ES3 / ES5 / ES6/ES2015 / ES2020 / ES2022 / ESNext
2.2 module - 模块系统
json
{
"compilerOptions": {
"module": "ESNext" // 保持 ES Module 不变
}
}可选值:CommonJS / ES6 / ES2015 / ES2020 / ESNext / Node16 / NodeNext
2.3 lib - 内置类型库
json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"]
}
}常用 lib:
DOM- 浏览器 APIDOM.Iterable- DOM 迭代器ES2020- ES2020 标准库WebWorker- Web WorkerScriptHost- 脚本宿主
2.4 outDir / rootDir
json
{
"compilerOptions": {
"outDir": "./dist", // 编译产物输出目录
"rootDir": "./src" // 源码根目录
}
}text
src/
├── index.ts
└── utils/
└── helper.ts
# 编译后
dist/
├── index.js
└── utils/
└── helper.js2.5 jsx - JSX 处理
json
{
"compilerOptions": {
"jsx": "react-jsx" // React 17+ 新 JSX 转换
}
}可选值:
preserve- 保留 JSXreact- 经典转换(React.createElement)react-jsx- 自动转换(17+)react-jsxdev- 开发模式
2.6 sourceMap
json
{
"compilerOptions": {
"sourceMap": true // 生成 .map 文件
}
}三、严格模式(strict)
strict: true 启用一组类型检查。
3.1 严格选项全家福
json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true, // 禁止隐式 any
"strictNullChecks": true, // 严格的 null 检查
"strictFunctionTypes": true, // 严格的函数类型
"strictBindCallApply": true, // bind/call/apply 严格
"strictPropertyInitialization": true, // 类的属性必须初始化
"alwaysStrict": true, // 始终严格模式
"useUnknownInCatchVariables": true, // catch 默认 unknown
"noImplicitReturns": true, // 函数必须有 return
"noFallthroughCasesInSwitch": true, // switch 不能省略 case
"noUncheckedIndexedAccess": true, // 索引访问可能 undefined
"noPropertyAccessFromIndexSignature": true
}
}3.2 strictNullChecks
typescript
// 启用前
function foo(x: number) {
return x.toFixed(2);
}
foo(null); // 编译通过,运行报错
// 启用后
function foo(x: number) {
return x.toFixed(2);
}
foo(null); // ❌ Argument of type 'null' is not assignable to parameter of type 'number'3.3 noImplicitAny
typescript
// ❌ 错误:参数隐式 any
function add(a, b) {
return a + b;
}
// ✅ 必须显式标注
function add(a: number, b: number) {
return a + b;
}3.4 noUncheckedIndexedAccess
typescript
// 启用前
const arr = [1, 2, 3];
const first = arr[0]; // 类型: number
// 启用后
const arr = [1, 2, 3];
const first = arr[0]; // 类型: number | undefined
first.toFixed(); // ❌ Object is possibly 'undefined'
first?.toFixed(); // ✅四、代码质量检查
4.1 冗余代码
json
{
"compilerOptions": {
"noUnusedLocals": true, // 禁止未使用的局部变量
"noUnusedParameters": true, // 禁止未使用的参数
"allowUnusedLabels": false, // 禁止未使用的 label
"allowUnreachableCode": false // 禁止执行不到的代码
}
}4.2 隐式错误检查
json
{
"compilerOptions": {
"noImplicitReturns": true, // 隐式 return 检查
"noFallthroughCasesInSwitch": true, // switch case 必 break
"noImplicitOverride": true, // override 必须标注
"noPropertyAccessFromIndexSignature": true
}
}4.3 杂项
json
{
"compilerOptions": {
"esModuleInterop": true, // ESM/CJS 互操作
"allowSyntheticDefaultImports": true, // 允许合成默认导入
"forceConsistentCasingInFileNames": true, // 文件名大小写必须一致
"isolatedModules": true, // 强制每个文件独立编译
"skipLibCheck": true // 跳过 .d.ts 文件检查
}
}推荐
新项目默认开启 skipLibCheck: true,加快编译速度。
五、路径解析配置
5.1 baseUrl
json
{
"compilerOptions": {
"baseUrl": "./" // 基准目录,通常为项目根
}
}5.2 paths - 路径别名
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"],
"@/*": ["./src/*"] // 也支持完整路径
}
}
}typescript
// 使用
import { Button } from '@components/Button';
import { formatDate } from '@utils/date';5.3 moduleResolution
json
{
"compilerOptions": {
"moduleResolution": "Bundler" // 推荐给 Vite/Webpack 5+ 用
}
}| 策略 | 适用场景 |
|---|---|
node | 传统 Node.js |
node16 / nodenext | Node.js 16+ ESM |
bundler | Vite / Webpack 5 |
classic | 已废弃 |
5.4 resolveJsonModule
json
{
"compilerOptions": {
"resolveJsonModule": true // 允许 import JSON
}
}typescript
import config from './config.json'; // 自动推导类型六、增量编译与性能
6.1 incremental
json
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./node_modules/.cache/tsbuildinfo"
}
}6.2 项目引用(project references)
json
// packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist"
}
}
// packages/ui/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist"
},
"references": [
{ "path": "../core" }
]
}
// tsconfig.json(根)
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/ui" }
]
}bash
# 增量编译
tsc --build
# 强制重新编译
tsc --build --force6.3 跳过检查
json
{
"compilerOptions": {
"skipLibCheck": true, // 跳过 .d.ts 检查
"noEmit": true, // 只检查不输出
"isolatedModules": true // 加快 swc/esbuild 等转译
}
}七、include / exclude / files
7.1 include - 包含
json
{
"include": [
"src/**/*",
"tests/**/*",
"types/**/*.d.ts"
]
}7.2 exclude - 排除
json
{
"exclude": [
"node_modules",
"dist",
"**/*.spec.ts"
]
}7.3 files - 精确指定
json
{
"files": [
"src/index.ts",
"src/types.ts"
]
}八、实战:项目配置模板
8.1 库项目
json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ES2020", "DOM"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}8.2 Vite + Vue 项目
json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"types": ["vite/client", "element-plus/global"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}8.3 Next.js 项目
json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{ "name": "next" }
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}8.4 Node.js 服务端项目
json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"sourceMap": true,
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}九、Monorepo 配置
9.1 项目结构
monorepo/
├── packages/
│ ├── core/
│ │ ├── tsconfig.json
│ │ └── src/
│ ├── ui/
│ │ ├── tsconfig.json
│ │ └── src/
│ └── utils/
│ ├── tsconfig.json
│ └── src/
├── tsconfig.base.json
└── tsconfig.json9.2 根配置
json
// tsconfig.base.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"composite": true, // 项目引用必须
"declaration": true,
"declarationMap": true
}
}
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/ui" },
{ "path": "./packages/utils" }
]
}9.3 子包配置
json
// packages/ui/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"references": [
{ "path": "../core" }
]
}十、配置项速查表
10.1 常用编译选项
| 选项 | 作用 | 推荐 |
|---|---|---|
target | 编译目标 | ES2020+ |
module | 模块系统 | ESNext/NodeNext |
lib | 内置类型库 | 按需 |
strict | 严格模式 | true |
noImplicitAny | 禁止隐式 any | true |
esModuleInterop | ESM/CJS 互操作 | true |
skipLibCheck | 跳过 .d.ts 检查 | true |
forceConsistentCasingInFileNames | 文件名大小写 | true |
10.2 模块解析
| 选项 | 作用 |
|---|---|
moduleResolution | 解析策略 |
baseUrl | 基准目录 |
paths | 路径别名 |
resolveJsonModule | 允许 import JSON |
allowJs | 允许 .js 文件 |
10.3 项目结构
| 选项 | 作用 |
|---|---|
outDir | 输出目录 |
rootDir | 源码根目录 |
include | 包含文件 |
exclude | 排除文件 |
files | 精确文件 |
references | 项目引用 |
10.4 输出控制
| 选项 | 作用 |
|---|---|
sourceMap | 生成 sourcemap |
declaration | 生成 .d.ts |
declarationMap | .d.ts map |
noEmit | 不输出文件 |
incremental | 增量编译 |
十一、常见错误
11.1 路径别名不生效
typescript
// ❌ 别名不生效
import { foo } from '@/utils';
// 解决:确保 tsconfig + 构建工具都配置了
// vite.config.ts
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}11.2 找不到 .d.ts
typescript
// ❌ 找不到模块 'xxx' 或其相应的类型声明
// 解决 1:安装 @types/xxx
// 解决 2:自己写 xxx.d.ts
// 解决 3:tsconfig 加 "noImplicitAny": false(不推荐)11.3 strict 太严格
json
{
"compilerOptions": {
"strict": false, // 关闭总开关
"noImplicitAny": true, // 但仍要部分
"strictNullChecks": true,
"strictFunctionTypes": false // 关闭最难的部分
}
}11.4 编译慢
json
{
"compilerOptions": {
"skipLibCheck": true, // 跳过 .d.ts
"isolatedModules": true, // 让 esbuild 处理
"incremental": true // 增量编译
}
}十二、本章小结
| 要点 | 关键 |
|---|---|
| 核心配置 | target / module / lib / strict |
| 严格模式 | strict + 多个细分选项 |
| 路径解析 | baseUrl + paths + moduleResolution |
| 性能优化 | skipLibCheck + incremental + isolatedModules |
| 项目引用 | composite + references 用于 monorepo |
| 配置模板 | 按项目类型选择(库/前端/Node) |
动手练习
- 初始化配置:运行
tsc --init,理解每个配置项 - strict 模式:打开所有 strict 选项,修掉所有报错
- 路径别名:配置
@/指向src/,验证生效 - monorepo:用项目引用搭建一个 mini monorepo
推荐阅读
- 📖 TypeScript Handbook - tsconfig — 编译选项全集
- 📖 TypeScript Performance — 性能优化建议
- 🌐 tsconfig/bases — 各场景的 tsconfig 模板
下一章:第 110 章:TS 在框架中的最佳实践 →