Typscript配置详解

61 阅读11分钟

tsconfig.json常用配置详解

1. 先看顶层配置:决定“项目范围”

extends

表示“继承另一个配置文件”。子配置会覆盖父配置,所以它很适合抽一个 tsconfig.base.json 放公共规则,再给前端、后端、测试分别写自己的 tsconfig.*.json。官方还说明,filesincludeexclude 会直接覆盖基配置里的同名项。

include

指定要纳入编译的文件或 glob 模式,比如 src/**/*tests/**/*。如果没有写 files,默认会匹配 **/*。它的目的就是告诉 TS 扫描哪些源码目录

exclude

表示在 include 的基础上排除哪些路径。要注意它不是绝对屏蔽:如果某个被排除文件又被别的文件 import 到,或者通过 files / types / reference 引入,它仍然可能进入编译。它的目的主要是缩小扫描范围,常见如排除 node_modules、构建产物、临时脚本。

files

显式列出要编译的文件白名单。适合文件特别少的小项目;文件多时通常用 include 更方便。

references

项目引用。适合 monorepo 或大型仓库,把大项目拆成多个小 TS 项目后互相引用。官方说明它可以提升构建和编辑器交互速度,也能强化模块边界。


2. 环境相关:决定“代码跑在哪、按什么 JS 能力编译”

target

指定输出的 JavaScript 目标版本,比如 ES2019ES2020ES2022ESNext。它的核心作用是:决定 TS 要不要把新语法降级。例如目标是 ES5 时,箭头函数会被转成普通函数;而且 target 还会影响默认的 lib

lib

指定要加载哪些内置类型库,比如 ES2022DOM。它决定你在类型层面能不能直接使用 documentMapPromise 等全局 API。目的就是把“运行环境提供了哪些 API”告诉 TypeScript

jsx

控制 .tsx 中 JSX 最终如何输出。它只影响从 .tsx 来的 JS 输出,React / Preact / 其他 JSX 框架都会用到。目的就是让 TS 知道 JSX 应该如何被保留或转换


3. 模块系统相关:决定“import/export 怎么理解”

module

指定模块系统,比如 commonjsesnextnodenextpreserve。官方现在的建议很明确:现代 Node 项目通常更可能需要 nodenext,而会交给 bundler 打包的项目通常更适合 preserveesnext。它的目的不是单纯决定输出长什么样,还会影响 TS 的类型检查和模块解析行为。

moduleResolution

指定模块解析策略,比如 bundlernode16nodenext。如果你是 Vite / Webpack / Rspack / esbuild 一类打包项目,常见会配合 bundler 思路;如果是现代 Node,则常用 node16 / nodenext。它的目的就是让 TS 以更接近真实运行时的方式找模块

baseUrl

设置非相对导入的基础目录。比如写了 baseUrl: "." 后,可以从项目根开始解析某些裸路径导入。官方还说明,这种解析优先级会高于 node_modules 查找。它的目的就是支持更短、更整洁的导入路径

paths

给导入路径做映射,比如把 @/* 指向 src/*。它会相对 baseUrl(如果设了)或 tsconfig 自身目录去解析。它的目的就是做别名映射,让代码里少写很长的相对路径。

esModuleInterop

常见于 Node 生态和历史 CommonJS 包混用场景。开启后,TS 会通过辅助函数改善 CommonJS 与 ES Module 的互操作,让默认导入等写法更顺手。它的目的就是降低 import 第三方老包时的兼容问题

types

默认情况下,所有可见的 @types 包都会参与编译;如果你显式写了 types,则只包含列出的那些类型包。它的目的就是控制全局类型污染,例如只保留 nodejestvite/client


4. 严格检查相关:决定“类型检查有多严格”

strict

最重要的总开关之一。官方说明它会启用一整组严格检查规则,从而提供更强的正确性保证;但未来 TS 升级时,strict 也可能带来新的报错。实践上,新项目通常建议直接开

noImplicitAny

禁止那些 TS 推断不出来、最后偷偷变成 any 的地方。目的就是避免类型系统失效却不自知

strictNullChecks

开启后,null / undefined 会被认真区分;像 find() 这种可能拿不到值的地方,TS 会要求你先判断再访问。目的就是减少空值运行时错误

noUnusedLocals

本地变量声明了但没用就报错。目的就是清理死代码、减少维护噪音

noUnusedParameters

函数参数没用就报错;不过以下划线 _ 开头的参数会被豁免。目的就是提醒你接口是否写多了、实现是否遗漏了逻辑

实际开发里,还很常见一起打开 noImplicitReturnsnoFallthroughCasesInSwitchuseUnknownInCatchVariablesexactOptionalPropertyTypesnoUncheckedIndexedAccess 这类更细的严格规则,用来进一步减少边界错误。


5. 输出与构建相关:决定“编译产物长什么样”

outDir

指定编译输出目录,比如 dist。如果不写,.js 会默认输出到源文件旁边。它的目的就是把源码和构建产物分开

rootDir

指定源码根目录,主要影响输出目录结构。官方特别强调:rootDir 不会影响哪些文件被纳入编译,它不参与 include / exclude / files 的匹配。它的目的主要是控制输出目录层级

noEmit

只做类型检查,不产出 JS、source map、声明文件。官方明确说,这很适合把真正转译工作交给 Babel、swc、bundler,而 TS 只负责类型检查。现代前端项目非常常见。

noEmitOnError

有类型错误时不输出构建产物。目的就是避免带着类型错误把产物发出去

sourceMap

生成 sourcemap,让调试器能映射回原始 TypeScript 源码。目的就是方便开发调试和报错定位

declaration

生成 .d.ts 声明文件。这个对发布 npm 库尤其重要,因为声明文件描述的是模块对外暴露的 API 类型。

declarationMap

.d.ts 再生成映射,编辑器可直接从声明跳到原始 .ts。官方特别建议:如果在用 project references,强烈考虑开启

incremental

保存上次编译的项目图信息到磁盘,生成 .tsbuildinfo,从而加快后续构建。目的就是提升大项目的二次编译速度

composite

给项目引用 / tsc --build 场景用。它会施加一些约束,让构建工具能更快判断项目是否已构建,并且会要求实现文件都被 includefiles 明确覆盖。目的就是支撑可组合、可缓存的多项目构建

skipLibCheck

跳过 .d.ts 声明文件检查,能节省编译时间,但官方也明确提示这是以类型精度为代价的;例如依赖树里存在两份不一致的类型定义时,它可能掩盖问题。它的目的通常是换速度,但不宜盲开成长期方案。


6. 另外一个很常见但容易忽略的选项

isolatedModules

当你的代码会被单文件转译器处理时很常见,比如 Babel、swc、esbuild 某些模式。官方说明它会在你写出“不能被单文件正确理解”的 TS 代码时给出警告,但不会改变代码运行逻辑本身。目的就是保证代码能安全交给单文件编译链处理


7. 一个常见的前端项目示例

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "Bundler",

    "jsx": "react-jsx",

    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,

    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },

    "noEmit": true,
    "sourceMap": true,
    "isolatedModules": true,
    "skipLibCheck": true,

    "types": ["vite/client"]
  },
  "include": ["src", "env.d.ts"],
  "exclude": ["dist", "node_modules"]
}

这个配置背后的思路是:
前端 bundler 负责真正打包,所以 TS 用 noEmit 只做类型检查;module / moduleResolution 则尽量对齐 bundler 行为;strict 打开保证代码质量;baseUrl + paths 用来做 @/ 别名;skipLibCheck 换取更快的开发编译。上述做法与官方关于 bundler、noEmit、模块配置、严格检查和路径映射的说明是一致的。


8. 你可以这样记忆

最常用的一批,优先记这 15 个就够了:

extendsincludeexcludetargetlibmodulemoduleResolutionstrictbaseUrlpathstypesrootDiroutDirnoEmitsourceMap

如果你是:

  • 前端应用:重点看 modulemoduleResolutionjsxnoEmitpaths
  • Node 服务:重点看 modulemoduleResolutiontargettypes: ["node"]
  • npm 库:重点看 declarationdeclarationMapoutDir
  • monorepo / 大仓:重点看 extendsreferencescompositeincremental

1. 创建基础配置

bash

npx tsc --init  # 生成默认 tsconfig.json

2. 主要配置分类

2.1 编译目标相关

json

{
  "compilerOptions": {
    /* 语言和环境 */
    "target": "es2020",               // 编译目标 ES 版本
    // 可选值: "es3", "es5", "es6"/"es2015", "es2020", "es2022", "esnext"
    
    "lib": ["es2020", "dom"],        // 要包含的库文件声明
    // 常用: ["es6", "dom"] / ["es2020", "dom", "dom.iterable"]
    
    "module": "commonjs",            // 模块系统
    // 可选值: "commonjs", "amd", "umd", "system", "es6"/"es2015", "es2020", "esnext"
    
    "rootDir": "./src",              // 源文件根目录
    "outDir": "./dist",              // 输出目录
    "declaration": true,             // 生成 .d.ts 声明文件
    "declarationDir": "./types",     // 声明文件输出目录
    "sourceMap": true,               // 生成 source map
    "sourceRoot": "./src",           // source map 中源文件根目录
    
    /* 模块解析 */
    "moduleResolution": "node",      // 模块解析策略
    "baseUrl": "./",                 // 解析非相对模块的基础目录
    "paths": {                       // 路径别名映射
      "@/*": ["src/*"],
      "@utils/*": ["src/utils/*"]
    },
    "resolveJsonModule": true,       // 允许导入 JSON 文件
    "allowSyntheticDefaultImports": true  // 允许默认导入
  }
}

2.2 严格模式相关

json

{
  "compilerOptions": {
    /* 严格类型检查选项 */
    "strict": true,                  // 启用所有严格类型检查
    
    // 可以单独配置的严格模式子选项
    "noImplicitAny": true,           // 禁止隐式 any 类型
    "strictNullChecks": true,        // 严格的 null 检查
    "strictFunctionTypes": true,     // 严格的函数类型检查
    "strictBindCallApply": true,     // 严格的 bind/call/apply 检查
    "strictPropertyInitialization": true,  // 严格的属性初始化检查
    "noImplicitThis": true,          // 禁止隐式 this
    "alwaysStrict": true,            // 总是以严格模式解析
    
    /* 额外检查 */
    "noUnusedLocals": true,          // 检查未使用的局部变量
    "noUnusedParameters": true,      // 检查未使用的参数
    "noImplicitReturns": true,       // 函数必须有返回值
    "noFallthroughCasesInSwitch": true, // 防止 switch 语句穿透
    "noUncheckedIndexedAccess": true,    // 索引访问时包含 undefined
    "exactOptionalPropertyTypes": true   // 精确的可选属性类型
  }
}

2.3 实验性/高级功能

json

{
  "compilerOptions": {
    /* 实验性选项 */
    "experimentalDecorators": true,  // 启用装饰器
    "emitDecoratorMetadata": true,   // 为装饰器生成元数据
    
    /* 高级选项 */
    "allowUnreachableCode": false,   // 不允许不可达代码
    "allowUnusedLabels": false,      // 不允许未使用标签
    "noImplicitOverride": true,      // 要求显式 override 修饰符
    
    /* 模块互操作 */
    "esModuleInterop": true,         // 改进 CommonJS/ES6 模块互操作
    "forceConsistentCasingInFileNames": true,  // 强制文件名大小写一致
    
    /* 编辑器集成 */
    "skipLibCheck": true,            // 跳过库类型检查(加快编译)
    "isolatedModules": true          // 确保每个文件可独立编译
  }
}

3. 文件包含/排除

json

{
  "include": [
    "src/**/*",           // 包含 src 目录下所有文件
    "types/**/*.d.ts",    // 包含自定义类型声明
    "test/**/*.ts"        // 包含测试文件
  ],
  
  "exclude": [
    "node_modules",       // 排除 node_modules
    "dist",               // 排除输出目录
    "**/*.test.ts",       // 排除测试文件(如果需要)
    "**/*.spec.ts"        // 排除测试文件
  ],
  
  "files": [              // 明确指定要编译的文件(优先级高于 include)
    "src/core.ts",
    "src/main.ts"
  ]
}

4. 扩展配置

json

{
  "extends": "./tsconfig.base.json",  // 继承基础配置
  
  "references": [                     // 项目引用(用于 monorepo)
    { "path": "./shared" },
    { "path": "./packages/core" }
  ]
}
  1.  前端项目(React/Vue)

json

{
  "compilerOptions": {
    "target": "es2015",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,                     // 与打包工具配合时设为 true
    "jsx": "react-jsx"                  // React 17+ JSX 转换
  },
  "include": ["src"]
}
  1. 检查配置有效性

bash

npx tsc --showConfig          # 显示最终配置
npx tsc --dry-run             # 检查而不编译
npx tsc --noEmit              # 只进行类型检查
  1. watch 模式

bash

tsc --watch                    # 监听文件变化
tsc --project tsconfig.dev.json --watch  # 指定配置文件

compilerOptions

即编译选项,主要告诉TS编译器:

  • 如何编译:目标语言版本,模块系统等
  • 编译什么:文件包含、排除规则
  • 编译到哪里: 输出目录和格式
  • 编译规则:类型检查严格程度

目标相关

{
  "compilerOptions": {
    "target": "es2020",           // 输出什么版本的 JS
    "module": "commonjs",         // 使用什么模块系统
    "lib": ["es2020", "dom"]      // 包含哪些内置 API 定义
  }

输出控制

{
  "compilerOptions": {
    "outDir": "./dist",           // 输出目录
    "outFile": "./bundle.js",     // 打包成单个文件
    "declaration": true,          // 生成 .d.ts 声明文件
    "sourceMap": true             // 生成 source map
  }
}

类型检查

{
  "compilerOptions": {
    "strict": true,               // 启用所有严格检查
    "noImplicitAny": true,        // 禁止隐式 any
    "strictNullChecks": true      // 严格空值检查
  }
}

模块解析

baseUrl 定义了非相对模块导入时的基础查找路径。

{
  "compilerOptions": {
    "baseUrl": "./",              // 模块解析基础路径
    "paths": {                    // 路径别名
      "@/*": ["src/*"]
    },
    "moduleResolution": "node"    // 使用 Node.js 解析策略
  }
}

编译选项作用的时机

编译流程图解

源代码 (.ts) 
    ↓
TypeScript 编译器 (tsc)
    ↓ (根据 compilerOptions 处理)
编译过程
    ├── 类型检查 (type checking)
    ├── 语法转换 (transpile)
    ├── 模块解析 (module resolution)
    └── 代码生成 (code generation)
    ↓
输出文件 (.js, .d.ts, .map)

重要选项详解

1. strict 家族

json

{
  "compilerOptions": {
    "strict": true,  // 相当于同时开启以下所有:
    // "noImplicitAny": true,
    // "strictNullChecks": true,
    // "strictFunctionTypes": true,
    // "strictBindCallApply": true,
    // "strictPropertyInitialization": true,
    // "noImplicitThis": true,
    // "alwaysStrict": true
  }
}

2. 模块相关

json

{
  "compilerOptions": {
    "esModuleInterop": true,           // 解决 CommonJS/ES6 互操作
    "allowSyntheticDefaultImports": true, // 允许默认导入
    "resolveJsonModule": true          // 允许导入 JSON
  }
}

3. 性能优化

json

{
  "compilerOptions": {
    "skipLibCheck": true,     // 跳过库文件检查(加快编译)
    "incremental": true,      // 增量编译
    "tsBuildInfoFile": ".tsbuildinfo" // 增量编译信息文件
  }
}

调试技巧:

bash

# 查看编译过程
tsc --listFiles                # 列出所有编译文件
tsc --diagnostics              # 输出诊断信息
tsc --extendedDiagnostics      # 详细诊断信息