TypeScript: TypeScript tsconfig.json 详解
最后更新:2026-08-26
tsconfig.json 是 TypeScript 项目的配置中心——它告诉编译器如何编译代码、检查类型、输出结果。理解配置选项,才能让 TypeScript 项目运转顺畅。
1. tsconfig.json 基础
(1) 创建配置文件
BASH
# 自动生成默认配置
tsc --init
# 生成带注释的详细配置
tsc --init --typescript
(2) 基本结构
JSON
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
(3) 顶层字段
| 字段 | 说明 |
|---|---|
compilerOptions |
编译器选项 |
include |
包含的文件(glob 模式) |
exclude |
排除的文件 |
files |
明确指定的文件列表 |
references |
项目引用(monorepo) |
extends |
继承另一个配置文件 |
2. 核心编译选项
(1) target——编译目标
指定编译后的 JavaScript 版本:
JSON
{
"compilerOptions": {
"target": "ES2020"
}
}
| 值 | 说明 | 推荐场景 |
|---|---|---|
"ES5" |
兼容旧浏览器 | IE11 支持 |
"ES2018" |
现代浏览器 | 一般 Web 项目 |
"ES2020" |
最新稳定特性 | 推荐 |
"ESNext" |
最新提案特性 | 前沿项目 |
💡 提示: target 只影响语法转换(如箭头函数→普通函数),不影响类型检查。类型检查由
lib 选项控制。
(2) module——模块系统
JSON
{
"compilerOptions": {
"module": "ESNext"
}
}
| 值 | 说明 | 推荐场景 |
|---|---|---|
"CommonJS" |
Node.js 默认 | Node 项目 |
"ESNext" / "ES2015" |
ES 模块 | 浏览器/Deno/Vite |
"UMD" |
通用模块 | 库发布 |
"System" |
SystemJS | 旧模块加载器 |
(3) moduleResolution——模块解析策略
JSON
{
"compilerOptions": {
"moduleResolution": "node"
}
}
| 值 | 说明 |
|---|---|
"node" |
Node.js 风格(推荐) |
"classic" |
旧版 TS 风格(不推荐) |
"bundler" |
Vite/esbuild 等打包工具风格(TS 5.0+) |
(4) lib——类型库
指定可用的内置类型声明:
JSON
{
"compilerOptions": {
"lib": ["ES2020", "DOM", "DOM.Iterable"]
}
}
| 值 | 提供的类型 |
|---|---|
"ES2020" |
Promise、Array.flat、BigInt 等 |
"DOM" |
document、window、HTMLElement 等 |
"DOM.Iterable" |
NodeList 的 for...of |
"ES2020.String" |
String 的 ES2020 方法 |
"ES2020.Promise" |
Promise.allSettled 等 |
💡 提示: target 自动包含对应的 lib。如果显式指定了 lib,就不再自动包含——需要手动列出所有需要的库。Web 项目通常需要
["ES2020", "DOM"]。
(5) outDir 与 rootDir
JSON
{
"compilerOptions": {
"outDir": "./dist", // 编译输出目录
"rootDir": "./src", // 源码根目录(保持目录结构)
"declaration": true, // 生成 .d.ts 声明文件
"sourceMap": true // 生成 .js.map 源码映射
}
}
3. 严格模式选项
(1) strict 全开
JSON
{
"compilerOptions": {
"strict": true
}
}
strict: true 等于同时开启以下所有选项:
| 选项 | 说明 |
|---|---|
strictNullChecks |
null/undefined 不能赋值给其他类型 |
strictFunctionTypes |
函数参数逆变检查 |
strictBindCallApply |
bind/call/apply 严格检查 |
strictPropertyInitialization |
类属性必须初始化 |
noImplicitAny |
禁止隐式 any |
noImplicitThis |
禁止 this 隐式为 any |
alwaysStrict |
输出 "use strict" |
(2) 逐项理解
TYPESCRIPT
// strictNullChecks: true
let name: string = null; // ❌ null 不能赋给 string
let name2: string | null = null; // ✅ 显式声明
// noImplicitAny: true
function greet(name) { // ❌ 参数隐式为 any
return name;
}
function greet2(name: string) { // ✅ 显式标注
return name;
}
// strictPropertyInitialization: true
class User {
name: string; // ❌ 属性未初始化
age: number = 0; // ✅ 有初始值
}
📌 建议:所有新项目都开 strict。 它是 TypeScript 类型安全的基石——虽然前期可能增加一些标注工作量,但能避免大量运行时错误。
▶ 示例:strict 模式前后对比
TYPESCRIPT
// strict: false 时——以下代码不报错但运行时可能崩溃
let name: string = null as any; // 运行时 name.toUpperCase() 崩溃
function greet(user) { // user 隐式 any
return user.name; // 无类型检查
}
// strict: true 时——编译时即捕获
let name2: string | null = null; // ✅ 必须显式声明 null
function greet2(user: { name: string }) { // ✅ 参数必须标注
return user.name;
}
4. 模块与路径配置
(1) 路径映射
JSON
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@utils/*": ["src/utils/*"],
"@components/*": ["src/components/*"]
}
}
}
(2) resolveJsonModule
JSON
{
"compilerOptions": {
"resolveJsonModule": true,
"esModuleInterop": true
}
}
TYPESCRIPT
// 允许导入 JSON 文件
import config from "./config.json";
console.log(config.port); // ✅
(3) allowJs 与 checkJs
JSON
{
"compilerOptions": {
"allowJs": true, // 允许编译 JS 文件
"checkJs": false // 不检查 JS 文件类型(只编译)
}
}
💡 用途: JS 项目逐步迁移到 TS 时,先开
allowJs 让 TS 和 JS 共存,再逐步添加类型。
5. 代码质量选项
JSON
{
"compilerOptions": {
"noUnusedLocals": true, // 报错:未使用的局部变量
"noUnusedParameters": true, // 报错:未使用的函数参数
"noImplicitReturns": true, // 报错:函数分支未返回值
"noFallthroughCasesInSwitch": true, // 报错:switch 穿透
"forceConsistentCasingInFileNames": true // 文件名大小写一致
}
}
(1) 效果演示
TYPESCRIPT
// noUnusedLocals: true
let unused = 42; // ❌ 未使用的变量
// noUnusedParameters: true
function handler(event: Event) { // ❌ event 未使用
console.log("触发");
}
// 修复:用 _ 前缀标记
function handler2(_event: Event) { // ✅ _ 前缀不报错
console.log("触发");
}
// noImplicitReturns: true
function getGrade(score: number): string {
if (score >= 90) return "A";
if (score >= 80) return "B";
// ❌ 缺少 else 分支的 return
}
// noFallthroughCasesInSwitch: true
switch (action) {
case "create":
createItem();
// ❌ 缺少 break——case 穿透
case "update":
updateItem();
break;
}
6. 常见配置模板
(1) Node.js 后端项目
JSON
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
(2) React 前端项目(Vite)
JSON
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
(3) 库项目(发布 npm 包)
JSON
{
"compilerOptions": {
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "node",
"declaration": true,
"declarationDir": "./dist/types",
"outDir": "./dist/esm",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
❓ 常见问题
Q strict 会不会让代码更难写?
A 初期可能需要更多类型标注(特别是 null 检查),但长期看减少了大量运行时 bug。建议从一开始就开 strict——习惯了之后反而觉得不严格才别扭。如果项目已经很大,可以逐步开启:先开 noImplicitAny,再开 strictNullChecks,最后全开 strict。
Q noEmit 是什么?为什么 Vite 项目要开?
A
noEmit: true 让 TypeScript 只做类型检查,不输出 JS 文件。Vite 项目由 Vite(esbuild)负责编译和打包,tsc 只负责类型检查——所以不需要 tsc 输出文件。CI 中用 tsc --noEmit 做类型检查,开发中由 Vite 实时编译。Q skipLibCheck 该不该开?
A 建议开启。skipLibCheck 跳过
.d.ts 文件的类型检查,能显著加快编译速度。缺点是可能错过第三方类型声明中的错误——但风险极低(@types 包有社区审核)。大型项目开启 skipLibCheck 能节省 30%+ 的编译时间。Q extends 继承配置有什么用?
A 项目有多个 tsconfig 时(如前端+Node 脚本+测试),用 extends 共享基础配置,只覆盖差异部分。
tsconfig.node.json 可以 extends tsconfig.json,只修改 target/module 等选项。避免配置重复。📖 小节
- tsconfig.json 是 TypeScript 项目的配置中心——compilerOptions、include、exclude 三个核心字段
- target 控制输出 JS 版本,module 控制模块系统,lib 控制可用类型库
strict: true开启所有严格检查——新项目必开- 路径映射(baseUrl + paths)用别名替代长相对路径
- 代码质量选项(noUnusedLocals/noImplicitReturns 等)进一步强化检查
- 不同项目类型有不同的推荐配置模板——Node 后端、React 前端、库项目
📝 作业
- 基础题(难度⭐):用
tsc --init生成默认 tsconfig.json,修改 target 为 ES2020,开启 strict,设置 outDir 为 dist。创建一个简单 TS 文件并编译验证。 - 进阶题(难度⭐⭐):配置一个支持路径别名
@/*→src/*的 tsconfig.json。创建 src/utils/math.ts 和 src/main.ts,在 main.ts 中用别名导入 math.ts 的函数。 - 挑战题(难度⭐⭐⭐):为 monorepo 项目设计配置层次——基础
tsconfig.base.json(共享选项)、packages/app/tsconfig.json(extends base,React 前端)、packages/server/tsconfig.json(extends base,Node 后端),用 references 连接两个子项目。