TypeScript 配置(tsconfig.json)
问题
如何配置 tsconfig.json?有哪些常用的编译选项?strict 模式包含哪些检查?
答案
tsconfig.json 是 TypeScript 项目的配置文件,定义编译选项、文件包含/排除规则等。理解配置选项有助于构建更安全、高效的 TypeScript 项目。
基础结构
tsconfig.json
{
"compilerOptions": {
// 编译器选项
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"],
"extends": "./tsconfig.base.json",
"references": []
}
顶层选项
| 选项 | 说明 |
|---|---|
compilerOptions | 编译器配置 |
include | 包含的文件(glob 模式) |
exclude | 排除的文件(glob 模式) |
files | 明确指定的文件列表 |
extends | 继承的配置文件 |
references | 项目引用(Monorepo) |
严格模式选项
strict
启用所有严格类型检查:
{
"compilerOptions": {
"strict": true
}
}
strict: true 等同于启用以下所有选项:
{
"compilerOptions": {
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true,
"useUnknownInCatchVariables": true
}
}
严格选项详解
// strictNullChecks
// 启用:null 和 undefined 是独立类型
let name: string = null; // 错误
// noImplicitAny
// 启用:不允许隐式 any
function log(message) {} // 错误:参数 message 隐式 any
// strictFunctionTypes
// 启用:函数参数类型严格检查
type Handler = (e: Event) => void;
const handler: Handler = (e: MouseEvent) => {}; // 错误
// strictPropertyInitialization
// 启用:类属性必须初始化
class User {
name: string; // 错误:未初始化
constructor() {}
}
// noImplicitThis
// 启用:不允许隐式 this
function getThis() {
return this; // 错误:this 类型为 any
}
// useUnknownInCatchVariables
// 启用:catch 变量类型为 unknown 而非 any
try {
// ...
} catch (e) {
// e: unknown
console.log(e.message); // 错误:需要类型检查
}
模块相关选项
module 和 moduleResolution
{
"compilerOptions": {
// 输出模块格式
"module": "ESNext",
// 模块解析策略
"moduleResolution": "bundler",
// 允许 ESM 语法导入 CommonJS
"esModuleInterop": true,
// 允许导入 JSON
"resolveJsonModule": true,
// 允许合成默认导出
"allowSyntheticDefaultImports": true
}
}
module 选项值
| 值 | 说明 |
|---|---|
CommonJS | Node.js 传统格式 |
ESNext | 最新 ES 模块 |
ES2020 | ES2020 模块 |
NodeNext | Node.js ESM |
AMD | AMD 格式 |
UMD | 通用模块 |
moduleResolution 选项值
| 值 | 说明 |
|---|---|
node | Node.js 传统解析(CommonJS) |
node16/nodenext | Node.js ESM 解析 |
bundler | 打包工具解析(Vite、Webpack) |
classic | TypeScript 早期解析(不推荐) |
输出相关选项
{
"compilerOptions": {
// 输出目录
"outDir": "./dist",
// 根目录
"rootDir": "./src",
// 输出目标
"target": "ES2020",
// 生成声明文件
"declaration": true,
"declarationDir": "./types",
// 生成 source map
"sourceMap": true,
// 移除注释
"removeComments": true,
// 不生成输出文件(只检查)
"noEmit": true
}
}
target 选项
| 值 | 说明 |
|---|---|
ES5 | 兼容旧浏览器 |
ES2015/ES6 | 支持 class、箭头函数等 |
ES2020 | 支持可选链、空值合并等 |
ES2022 | 支持类静态块、top-level await |
ESNext | 最新 ES 特性 |
路径映射
baseUrl 和 paths
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"],
"@types/*": ["src/types/*"]
}
}
}
使用示例:
// 不使用路径映射
import { Button } from '../../../components/Button';
// 使用路径映射
import { Button } from '@components/Button';
注意
路径映射只是类型检查时的别名。运行时解析需要配置打包工具(Vite、Webpack)或使用 tsc-alias。
类型检查增强
{
"compilerOptions": {
// 不允许未使用的局部变量
"noUnusedLocals": true,
// 不允许未使用的参数
"noUnusedParameters": true,
// 不允许隐式返回
"noImplicitReturns": true,
// 检查 switch 穷尽
"noFallthroughCasesInSwitch": true,
// 检查索引签名访问
"noUncheckedIndexedAccess": true,
// 精确可选属性类型
"exactOptionalPropertyTypes": true,
// 不允许覆盖访问修饰符
"noImplicitOverride": true
}
}
noUncheckedIndexedAccess
// noUncheckedIndexedAccess: false(默认)
const arr: string[] = [];
const item = arr[0]; // string
// noUncheckedIndexedAccess: true
const item = arr[0]; // string | undefined
// 必须检查
if (item !== undefined) {
console.log(item.toUpperCase());
}
exactOptionalPropertyTypes
// exactOptionalPropertyTypes: false(默认)
interface User {
name?: string;
}
const user: User = { name: undefined }; // OK
// exactOptionalPropertyTypes: true
const user: User = { name: undefined }; // 错误
// 可选属性不能显式赋值 undefined
库和类型定义
{
"compilerOptions": {
// 内置库
"lib": ["ES2020", "DOM", "DOM.Iterable"],
// 类型根目录
"typeRoots": ["./node_modules/@types", "./src/types"],
// 明确包含的类型包
"types": ["node", "jest"],
// 跳过库文件检查(加速编译)
"skipLibCheck": true
}
}
lib 常用值
| 值 | 说明 |
|---|---|
ES5 | ES5 核心 |
ES2015-ES2023 | 各版本特性 |
ESNext | 最新特性 |
DOM | 浏览器 DOM API |
DOM.Iterable | DOM 可迭代类型 |
WebWorker | Web Worker API |
常用配置模板
React 项目
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"],
"exclude": ["node_modules"]
}
Node.js 项目
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
库/NPM 包
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"skipLibCheck": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
项目引用(Monorepo)
tsconfig.json (root)
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" },
{ "path": "./packages/ui" }
]
}
packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"references": [
{ "path": "../utils" }
]
}
常见面试问题
Q1: strict 模式包含哪些检查?
答案:
{
"strict": true
}
// 等同于开启以下所有选项:
| 选项 | 作用 |
|---|---|
strictNullChecks | null/undefined 需显式处理 |
strictFunctionTypes | 函数参数逆变检查 |
strictBindCallApply | bind/call/apply 类型检查 |
strictPropertyInitialization | 类属性必须初始化 |
noImplicitAny | 禁止隐式 any |
noImplicitThis | 禁止隐式 this |
alwaysStrict | 输出 "use strict" |
useUnknownInCatchVariables | catch 变量为 unknown |
Q2: module 和 moduleResolution 如何选择?
答案:
// 前端项目(Vite/Webpack)
{
"module": "ESNext",
"moduleResolution": "bundler"
}
// Node.js ESM
{
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
// Node.js CommonJS
{
"module": "CommonJS",
"moduleResolution": "node"
}
// 库(支持多种环境)
{
"module": "ESNext",
"moduleResolution": "bundler"
}
规则:
bundler:配合打包工具使用NodeNext:Node.js 原生 ESMnode:Node.js CommonJS
Q3: paths 配置后运行时报错怎么办?
答案:
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
TypeScript paths 只影响编译时类型检查,不影响运行时模块解析。需要配置运行时别名:
// Vite: vite.config.ts
import { resolve } from 'path';
export default {
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
}
};
// Webpack: webpack.config.js
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
};
// Node.js: 使用 tsconfig-paths
// package.json
{
"scripts": {
"dev": "ts-node -r tsconfig-paths/register src/index.ts"
}
}
// 或使用 tsc-alias 编译后处理
{
"scripts": {
"build": "tsc && tsc-alias"
}
}
Q4: 如何加速 TypeScript 编译?
答案:
{
"compilerOptions": {
// 跳过库类型检查
"skipLibCheck": true,
// 增量编译
"incremental": true,
"tsBuildInfoFile": "./.tsbuildinfo",
// 项目引用(增量构建)
"composite": true
}
}
其他优化:
- 使用 esbuild/swc:比 tsc 快 10-100x
- Fork TS Checker:类型检查在独立进程
- 项目引用:大型 Monorepo 增量构建
- exclude 合理:排除不必要的文件
Q5: 如何配置不同环境的 tsconfig?
答案:
tsconfig.base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "bundler"
}
}
tsconfig.json (开发)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"sourceMap": true,
"noEmit": true
},
"include": ["src"]
}
tsconfig.build.json (构建)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"declaration": true,
"outDir": "dist",
"removeComments": true
},
"include": ["src"],
"exclude": ["**/*.test.ts", "**/*.spec.ts"]
}
# 使用指定配置
tsc -p tsconfig.build.json