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 等选项。避免配置重复。

📖 小节

📝 作业

  1. 基础题(难度⭐):用 tsc --init 生成默认 tsconfig.json,修改 target 为 ES2020,开启 strict,设置 outDir 为 dist。创建一个简单 TS 文件并编译验证。
  2. 进阶题(难度⭐⭐):配置一个支持路径别名 @/*src/* 的 tsconfig.json。创建 src/utils/math.ts 和 src/main.ts,在 main.ts 中用别名导入 math.ts 的函数。
  3. 挑战题(难度⭐⭐⭐):为 monorepo 项目设计配置层次——基础 tsconfig.base.json(共享选项)、packages/app/tsconfig.json(extends base,React 前端)、packages/server/tsconfig.json(extends base,Node 后端),用 references 连接两个子项目。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏