跳到主要内容

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 选项值

说明
CommonJSNode.js 传统格式
ESNext最新 ES 模块
ES2020ES2020 模块
NodeNextNode.js ESM
AMDAMD 格式
UMD通用模块

moduleResolution 选项值

说明
nodeNode.js 传统解析(CommonJS)
node16/nodenextNode.js ESM 解析
bundler打包工具解析(Vite、Webpack)
classicTypeScript 早期解析(不推荐)

输出相关选项

{
"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 常用值

说明
ES5ES5 核心
ES2015-ES2023各版本特性
ESNext最新特性
DOM浏览器 DOM API
DOM.IterableDOM 可迭代类型
WebWorkerWeb 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
}
// 等同于开启以下所有选项:
选项作用
strictNullChecksnull/undefined 需显式处理
strictFunctionTypes函数参数逆变检查
strictBindCallApplybind/call/apply 类型检查
strictPropertyInitialization类属性必须初始化
noImplicitAny禁止隐式 any
noImplicitThis禁止隐式 this
alwaysStrict输出 "use strict"
useUnknownInCatchVariablescatch 变量为 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 原生 ESM
  • node: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
}
}

其他优化:

  1. 使用 esbuild/swc:比 tsc 快 10-100x
  2. Fork TS Checker:类型检查在独立进程
  3. 项目引用:大型 Monorepo 增量构建
  4. 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

相关链接