Skip to content
第 109 / 250 章前端⏱ 10 分钟阅读

第 109 章:tsconfig.json 详解

学习目标

  • 掌握 tsconfig.json 的完整配置
  • 理解 strict 模式与各类检查
  • 学会项目引用与 monorepo 配置
  • 能根据项目类型选择合适的配置模板

一、tsconfig.json 基础

1.1 初始化配置

bash
# 交互式生成
npx tsc --init

# 生成 tsconfig.json

1.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 - 浏览器 API
  • DOM.Iterable - DOM 迭代器
  • ES2020 - ES2020 标准库
  • WebWorker - Web Worker
  • ScriptHost - 脚本宿主

2.4 outDir / rootDir

json
{
  "compilerOptions": {
    "outDir": "./dist",     // 编译产物输出目录
    "rootDir": "./src"      // 源码根目录
  }
}
text
src/
├── index.ts
└── utils/
    └── helper.ts

# 编译后
dist/
├── index.js
└── utils/
    └── helper.js

2.5 jsx - JSX 处理

json
{
  "compilerOptions": {
    "jsx": "react-jsx"     // React 17+ 新 JSX 转换
  }
}

可选值:

  • preserve - 保留 JSX
  • react - 经典转换(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 / nodenextNode.js 16+ ESM
bundlerVite / 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 --force

6.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.json

9.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禁止隐式 anytrue
esModuleInteropESM/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)

动手练习

  1. 初始化配置:运行 tsc --init,理解每个配置项
  2. strict 模式:打开所有 strict 选项,修掉所有报错
  3. 路径别名:配置 @/ 指向 src/,验证生效
  4. monorepo:用项目引用搭建一个 mini monorepo

推荐阅读


下一章第 110 章:TS 在框架中的最佳实践

本站基于 VitePress 构建 · 由 Codebook 团队维护