跳转至

TypeScript 配置详解 (tsconfig.json)

tsconfig.json 是 TypeScript 项目的核心配置文件,它定义了 TypeScript 编译器的行为、编译选项以及项目结构。正确配置 tsconfig.json 对于优化开发体验、提高代码质量和确保项目一致性至关重要。

1. tsconfig.json 概述

1.1 配置文件的作用

tsconfig.json 文件的主要作用包括:

  • 指定编译选项:控制 TypeScript 如何编译代码
  • 定义项目结构:指定哪些文件需要编译,哪些需要排除
  • 启用/禁用语言特性:控制 TypeScript 的语言特性
  • 集成开发工具:为 IDE 和构建工具提供配置信息
  • 确保团队一致性:统一团队成员的开发环境

1.2 配置文件的位置

tsconfig.json 应该放在项目的根目录。TypeScript 编译器会从当前目录开始向上查找 tsconfig.json 文件。

1.3 创建配置文件

1
2
3
4
5
# 使用 TypeScript 编译器生成默认配置
npx tsc --init

# 或者手动创建
touch tsconfig.json

2. 配置文件结构

2.1 基本结构

一个典型的 tsconfig.json 文件包含以下部分:

{
  // 编译选项
  "compilerOptions": {
    // 目标 JavaScript 版本
    "target": "es2016",

    // 模块系统
    "module": "commonjs",

    // 输出目录
    "outDir": "./dist",

    // 严格模式
    "strict": true,

    // 其他选项...
  },

  // 包含的文件
  "include": [
    "src/**/*"
  ],

  // 排除的文件
  "exclude": [
    "node_modules",
    "dist"
  ],

  // 扩展配置
  "extends": "./tsconfig.base.json",

  // 文件引用
  "references": [
    { "path": "./packages/core" }
  ]
}

2.2 配置继承

TypeScript 支持配置继承,可以创建一个基础配置:

// tsconfig.base.json
{
  "compilerOptions": {
    "strict": true,
    "target": "es2016",
    "module": "commonjs"
  }
}

// tsconfig.json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

3. 编译选项详解

3.1 目标版本相关

target

指定编译后的 JavaScript 目标版本。

1
2
3
4
5
{
  "compilerOptions": {
    "target": "es2016"  // ES2016, ES2020, ES2022, ESNext
  }
}

可选值: - es3, es5, es6/es2015 - es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext

lib

指定要包含的库文件定义。

1
2
3
4
5
{
  "compilerOptions": {
    "lib": ["es6", "dom", "dom.iterable", "esnext"]
  }
}

常用库: - es5, es6, es2015, es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext - dom, dom.iterable, webworker - scripthost

module

指定模块系统。

1
2
3
4
5
{
  "compilerOptions": {
    "module": "commonjs"  // commonjs, amd, umd, system, es6/es2015, es2020, esnext
  }
}

3.2 输出控制相关

outDir

指定输出目录。

1
2
3
4
5
{
  "compilerOptions": {
    "outDir": "./dist"
  }
}

outFile

将所有输出合并为一个文件。

1
2
3
4
5
{
  "compilerOptions": {
    "outFile": "./dist/bundle.js"
  }
}

rootDir

指定输入文件的根目录。

1
2
3
4
5
{
  "compilerOptions": {
    "rootDir": "./src"
  }
}

declarationdeclarationDir

生成声明文件。

1
2
3
4
5
6
{
  "compilerOptions": {
    "declaration": true,
    "declarationDir": "./types"
  }
}

sourceMap

生成 source map 文件。

1
2
3
4
5
6
7
{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSourceMap": false,
    "inlineSources": false
  }
}

3.3 严格类型检查

strict

启用所有严格类型检查选项。

1
2
3
4
5
{
  "compilerOptions": {
    "strict": true
  }
}

等同于同时启用以下所有选项:

noImplicitAny

禁止隐式的 any 类型。

1
2
3
4
5
6
7
8
9
// 错误:参数 'x' 隐式具有 'any' 类型
function fn(x) {
  return x * 2;
}

// 正确:明确指定类型
function fn(x: number) {
  return x * 2;
}

strictNullChecks

启用严格的 null 检查。

1
2
3
4
5
let x: number;
x = null;  // 错误:不能将类型 "null" 分配给类型 "number"

let y: number | null;
y = null;  // 正确

strictFunctionTypes

对函数类型进行严格检查。

1
2
3
4
5
6
type Handler = (request: string) => void;

// 错误:参数类型不兼容
const handler: Handler = (request: any) => {
  console.log(request);
};

strictBindCallApply

bindcallapply 进行严格检查。

1
2
3
4
5
6
function fn(x: number, y: number) {
  return x + y;
}

// 错误:参数数量不匹配
fn.call(null, 1, 2, 3);

strictPropertyInitialization

确保类的属性被初始化。

1
2
3
4
5
6
7
class User {
  name: string;  // 错误:属性 'name' 没有初始化表达式

  constructor() {
    this.name = "John";  // 正确:在构造函数中初始化
  }
}

noImplicitThis

禁止隐式的 this 类型。

class Rectangle {
  width: number;
  height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  // 错误:'this' 隐式具有类型 'any'
  getArea() {
    return this.width * this.height;
  }

  // 正确:明确指定 'this' 类型
  getArea2(this: Rectangle) {
    return this.width * this.height;
  }
}

alwaysStrict

以严格模式解析代码,并在每个文件开头添加 "use strict"

3.4 模块解析

moduleResolution

指定模块解析策略。

1
2
3
4
5
{
  "compilerOptions": {
    "moduleResolution": "node"  // node, classic
  }
}

baseUrl

指定模块解析的基础目录。

1
2
3
4
5
{
  "compilerOptions": {
    "baseUrl": "./src"
  }
}

paths

配置模块路径映射。

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@utils/*": ["utils/*"],
      "@types/*": ["types/*"]
    }
  }
}

rootDirs

指定多个根目录。

1
2
3
4
5
{
  "compilerOptions": {
    "rootDirs": ["./src", "./generated"]
  }
}

3.5 其他重要选项

esModuleInterop

启用 ES 模块和 CommonJS 模块的互操作性。

1
2
3
4
5
{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

allowSyntheticDefaultImports

允许从没有默认导出的模块中进行默认导入。

1
2
3
4
5
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true
  }
}

experimentalDecorators

启用实验性的装饰器支持。

1
2
3
4
5
{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

emitDecoratorMetadata

为装饰器发出元数据。

1
2
3
4
5
{
  "compilerOptions": {
    "emitDecoratorMetadata": true
  }
}

jsx

控制 JSX 的编译方式。

1
2
3
4
5
{
  "compilerOptions": {
    "jsx": "react"  // preserve, react, react-native, react-jsx, react-jsxdev
  }
}

skipLibCheck

跳过库文件的类型检查。

1
2
3
4
5
{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

forceConsistentCasingInFileNames

强制文件名大小写一致。

1
2
3
4
5
{
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true
  }
}

4. 文件包含与排除

4.1 include

指定要包含的文件或目录。

1
2
3
4
5
6
7
{
  "include": [
    "src/**/*",           // src 目录下的所有文件
    "tests/**/*.ts",      // tests 目录下的所有 .ts 文件
    "typings/**/*.d.ts"   // typings 目录下的所有声明文件
  ]
}

4.2 exclude

指定要排除的文件或目录。

1
2
3
4
5
6
7
8
{
  "exclude": [
    "node_modules",       // 排除 node_modules
    "dist",              // 排除输出目录
    "**/*.spec.ts",      // 排除所有测试文件
    "**/*.test.ts"       // 排除所有测试文件
  ]
}

4.3 files

明确指定要编译的文件列表。

1
2
3
4
5
6
7
{
  "files": [
    "src/core.ts",
    "src/utils.ts",
    "src/main.ts"
  ]
}

5. 项目引用

TypeScript 3.0 引入了项目引用功能,支持大型项目的模块化构建。

5.1 基本配置

// tsconfig.json (根配置)
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true
  },
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" },
    { "path": "./packages/app" }
  ]
}

// packages/core/tsconfig.json
{
  "compilerOptions": {
    "outDir": "../../dist/core",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

5.2 构建命令

1
2
3
4
5
6
7
8
# 构建所有项目
tsc --build

# 构建特定项目
tsc --build packages/core

# 清理构建输出
tsc --build --clean

6. 常见配置场景

6.1 Node.js 项目配置

{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "lib": ["es2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

6.2 React 项目配置

{
  "compilerOptions": {
    "target": "es5",
    "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,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

6.3 库项目配置

{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "lib": ["es2015"],
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
}

6.4 全栈项目配置

// 共享配置 (tsconfig.base.json)
{
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

// 前端配置 (tsconfig.client.json)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "react-jsx",
    "outDir": "./dist/client"
  },
  "include": ["src/client/**/*"]
}

// 后端配置 (tsconfig.server.json)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "outDir": "./dist/server"
  },
  "include": ["src/server/**/*"]
}

7. 配置最佳实践

7.1 版本控制

tsconfig.json 提交到版本控制系统,确保团队一致性。

7.2 环境特定配置

为不同环境创建不同的配置文件:

// tsconfig.json (基础配置)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    // 公共配置
  }
}

// tsconfig.dev.json (开发环境)
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "sourceMap": true,
    "inlineSources": true
  }
}

// tsconfig.prod.json (生产环境)
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "sourceMap": false,
    "declaration": false
  }
}

7.3 性能优化

  1. 启用增量编译

    1
    2
    3
    4
    5
    6
    {
      "compilerOptions": {
        "incremental": true,
        "tsBuildInfoFile": "./.tsbuildinfo"
      }
    }
    

  2. 跳过库检查

    1
    2
    3
    4
    5
    {
      "compilerOptions": {
        "skipLibCheck": true
      }
    }
    

  3. 使用项目引用:对于大型项目,使用项目引用提高构建性能。

7.4 代码质量

  1. 启用严格模式:始终启用 strict: true
  2. 启用所有严格检查:根据项目需求启用额外的严格检查
  3. 生成声明文件:对于库项目,生成声明文件
  4. 启用 source map:便于调试

8. 常见问题与解决方案

8.1 模块解析失败

问题:无法找到模块声明。

解决方案

1
2
3
4
5
6
7
8
9
{
  "compilerOptions": {
    "moduleResolution": "node",
    "baseUrl": "./",
    "paths": {
      "*": ["node_modules/*", "src/types/*"]
    }
  }
}

8.2 类型定义冲突

问题:多个类型定义冲突。

解决方案

1
2
3
4
5
{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

8.3 构建性能问题

问题:构建速度慢。

解决方案

1
2
3
4
5
6
{
  "compilerOptions": {
    "incremental": true,
    "composite": true
  }
}

8.4 与第三方库兼容

问题:第三方库没有类型定义。

解决方案: 1. 安装 @types/ 包 2. 创建自定义声明文件 3. 使用 declare module 语法

9. 工具集成

9.1 VS Code 集成

VS Code 会自动读取 tsconfig.json 文件,提供智能提示和错误检查。

9.2 Webpack 集成

使用 ts-loaderawesome-typescript-loader

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
};

9.3 ESLint 集成

使用 @typescript-eslint