目录

第十章 编译配置

TypeScript编译器(tsc)提供了丰富的配置选项,通过tsconfig.json文件可以精细控制编译过程。理解这些配置选项对于构建高质量的TypeScript项目至关重要。

10.1 tsconfig.json基础

10.1.1 配置文件结构

{
  "compilerOptions": {
    // 编译选项
  },
  "include": [
    // 包含的文件
  ],
  "exclude": [
    // 排除的文件
  ],
  "extends": "./base.json",  // 继承基础配置
  "files": [
    // 明确的文件列表
  ],
  "references": [
    // 项目引用
  ]
}

10.1.2 配置继承

// base.json
{
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true
  }
}
 
// tsconfig.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "outDir": "./dist",
    // strict和esModuleInterop被继承
  }
}

10.2 核心编译选项

10.2.1 目标与模块

{
  "compilerOptions": {
    "target": "ES2020",           // 编译目标JavaScript版本
    "module": "ESNext",           // 模块系统
    "moduleResolution": "node",   // 模块解析策略
    "lib": ["ES2020", "DOM"],     // 包含的库类型
    "jsx": "react-jsx"            // JSX处理方式
  }
}

target选项: - “ES3”(默认) - “ES5” - “ES6”/“ES2015” - “ES2016” 到 “ES2023” - “ESNext”

module选项: - “CommonJS” - “AMD” - “UMD” - “System” - “ES6”/“ES2015”/“ES2020”/“ES2022”/“ESNext” - “Node16” - “NodeNext”

10.2.2 严格类型检查

{
  "compilerOptions": {
    "strict": true,              // 启用所有严格类型检查
 
    // 或者单独配置
    "noImplicitAny": true,       // 禁止隐式any
    "strictNullChecks": true,    // 严格null检查
    "strictFunctionTypes": true, // 严格函数类型
    "strictBindCallApply": true, // 严格bind/call/apply
    "strictPropertyInitialization": true, // 严格属性初始化
    "noImplicitThis": true,      // 禁止隐式this
    "alwaysStrict": true         // 始终使用严格模式
  }
}

10.2.3 输出配置

{
  "compilerOptions": {
    "outDir": "./dist",          // 输出目录
    "outFile": "./bundle.js",    // 合并输出文件(仅限AMD/System)
    "rootDir": "./src",          // 源代码根目录
    "removeComments": true,      // 移除注释
    "sourceMap": true,           // 生成source map
    "declaration": true,         // 生成.d.ts声明文件
    "declarationMap": true,      // 生成声明文件source map
    "declarationDir": "./types"  // 声明文件输出目录
  }
}

10.2.4 路径与别名

{
  "compilerOptions": {
    "baseUrl": ".",              // 基础路径
    "paths": {
      "@/*": ["src/*"],          // 路径别名
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"],
      "@shared/*": ["../shared/src/*"]  // 指向外部目录
    },
    "rootDirs": ["src", "generated"],  // 虚拟根目录
    "typeRoots": ["./types", "./node_modules/@types"]
  }
}

10.2.5 JavaScript支持

{
  "compilerOptions": {
    "allowJs": true,             // 允许编译JavaScript文件
    "checkJs": true,             // 检查JavaScript文件
    "maxNodeModuleJsDepth": 1,   // node_modules中JS检查深度
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

10.3 工程引用(Project References)

10.3.1 多项目配置

// 根目录 tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./src/common" },
    { "path": "./src/app" },
    { "path": "./src/tests" }
  ]
}
 
// src/common/tsconfig.json
{
  "compilerOptions": {
    "composite": true,           // 必须启用用于项目引用
    "declaration": true,
    "outDir": "../../dist/common"
  },
  "include": ["./**/*"]
}
 
// src/app/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "outDir": "../../dist/app"
  },
  "references": [
    { "path": "../common" }       // 依赖common项目
  ],
  "include": ["./**/*"]
}

10.3.2 增量编译

{
  "compilerOptions": {
    "composite": true,           // 项目引用必需
    "incremental": true,         // 增量编译
    "tsBuildInfoFile": "./.tsbuildinfo"  // 构建信息文件
  }
}

10.4 高级配置

10.4.1 装饰器配置

{
  "compilerOptions": {
    "experimentalDecorators": true,     // 启用装饰器
    "emitDecoratorMetadata": true       // 发出装饰器元数据
  }
}

10.4.2 模块解析

{
  "compilerOptions": {
    "moduleResolution": "node",         // 或 "classic"
    "esModuleInterop": true,            // ES模块互操作
    "allowSyntheticDefaultImports": true, // 允许默认导入
    "forceConsistentCasingInFileNames": true,  // 强制文件名大小写一致
    "resolveJsonModule": true           // 允许导入JSON
  }
}

10.4.3 代码质量选项

{
  "compilerOptions": {
    // 未使用代码检测
    "noUnusedLocals": true,           // 未使用局部变量报错
    "noUnusedParameters": true,       // 未使用参数报错
    "noImplicitReturns": true,        // 所有代码路径必须有返回
    "noFallthroughCasesInSwitch": true, // 禁止switch fallthrough
 
    // 类型检查增强
    "noUncheckedIndexedAccess": true, // 索引访问可能undefined
    "exactOptionalPropertyTypes": true, // 精确可选属性类型
    "noImplicitOverride": true,       // 需要override关键字
    "noPropertyAccessFromIndexSignature": true,  // 索引签名需要方括号
 
    // 弃用和错误
    "allowUnreachableCode": false,    // 不允许不可达代码
    "allowUnusedLabels": false        // 不允许未使用标签
  }
}

10.4.4 emit相关选项

{
  "compilerOptions": {
    "importHelpers": true,            // 从tslib导入辅助函数
    "noEmitHelpers": true,            // 不内联辅助函数
    "downlevelIteration": true,       // 降级迭代器支持
    "emitBOM": false,                 // 不输出BOM
    "newLine": "lf",                  // 换行符
    "stripInternal": true,            // 不输出@internal
    "preserveConstEnums": false,      // 是否保留const enum
    "isolatedModules": true           // 确保文件可独立编译
  }
}

10.5 常见配置场景

10.5.1 Node.js项目

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

10.5.2 React项目

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,                   // 由Vite/ webpack处理emit
    "isolatedModules": true,
    "resolveJsonModule": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

10.5.3 库开发配置

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "ESNext",
    "moduleResolution": "node",
    "lib": ["ES2020", "DOM"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "inlineSources": true,
    "stripInternal": true,
    "isolatedModules": true,
    "noEmitOnError": true
  },
  "include": ["src/**/*"],
  "exclude": ["**/*.spec.ts", "**/*.test.ts"]
}

10.5.4 严格模式配置

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022"],
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  }
}

10.6 编译器API

10.6.1 程序化编译

import * as ts from "typescript";
 
function compile(fileNames: string[], options: ts.CompilerOptions): void {
  const program = ts.createProgram(fileNames, options);
  const emitResult = program.emit();
 
  const allDiagnostics = ts
    .getPreEmitDiagnostics(program)
    .concat(emitResult.diagnostics);
 
  allDiagnostics.forEach(diagnostic => {
    if (diagnostic.file) {
      const { line, character } = ts.getLineAndCharacterOfPosition(
        diagnostic.file,
        diagnostic.start!
      );
      const message = ts.flattenDiagnosticMessageText(
        diagnostic.messageText,
        "\n"
      );
      console.log(
        `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`
      );
    } else {
      console.log(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"));
    }
  });
 
  const exitCode = emitResult.emitSkipped ? 1 : 0;
  console.log(`Process exiting with code '${exitCode}'.`);
  process.exit(exitCode);
}
 
compile(process.argv.slice(2), {
  noEmitOnError: true,
  noImplicitAny: true,
  target: ts.ScriptTarget.ES5,
  module: ts.ModuleKind.CommonJS
});

10.6.2 类型检查器

import * as ts from "typescript";
 
function visit(node: ts.Node) {
  console.log(ts.SyntaxKind[node.kind]);
  ts.forEachChild(node, visit);
}
 
const program = ts.createProgram(["example.ts"], {});
const sourceFile = program.getSourceFile("example.ts")!;
visit(sourceFile);

10.7 诊断与调试

10.7.1 显示配置

# 显示编译器配置
tsc --showConfig
 
# 详细输出
tsc --verbose
 
# 跟踪解析过程
tsc --traceResolution
 
# 显示版本
tsc --version
 
# 显示帮助
tsc --help --all

10.7.2 性能分析

{
  "compilerOptions": {
    "generateTrace": "./trace",    // 生成性能跟踪文件
    "explainFiles": true            // 解释文件包含原因
  }
}

10.8 迁移配置策略

10.8.1 渐进式严格化

// 阶段1: 基本严格
{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": true,
    "strictNullChecks": false
  }
}
 
// 阶段2: 启用strictNullChecks
{
  "compilerOptions": {
    "strict": false,
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}
 
// 阶段3: 完全严格
{
  "compilerOptions": {
    "strict": true
  }
}

10.9 小结

TypeScript编译配置是项目构建的基础,关键要点包括:

1. 基础配置:target、module、strict三大核心选项 2. 路径配置:paths和baseUrl简化模块导入 3. 工程引用:composite和references实现大型项目构建优化 4. 严格模式:strict家族选项确保类型安全 5. 代码质量:未使用检测、隐式返回检查等提升代码质量 6. 项目场景:根据Node.js、React、库开发等不同场景选择合适配置

合理配置tsconfig.json可以显著提升开发体验和代码质量,建议新项目直接使用严格模式配置。