Skip to content

当一个文件夹里只有一个 .ts 文件时,我们可以简单地使用 tsc myFile.ts 来编译它。但当项目变得复杂,包含数十甚至数百个文件时,我们需要一个更系统的方式来管理。我们需要一个地方来告诉 TypeScript 编译器:

  • 这个项目的“根”在哪里?
  • 哪些文件应该被包含在编译中,哪些应该被排除?
  • 我们希望将 TypeScript 代码编译成哪个版本的 JavaScript?
  • 我们希望代码检查的严格程度是怎样的?

所有这些问题的答案,都存放在一个至关重要的文件中——tsconfig.json。这个文件是任何一个 TypeScript 项目的大脑指挥中心。一个配置良好、意图清晰的 tsconfig.json 是专业 TypeScript 项目的标志。

tsconfig.json 的诞生

这个文件本身就是一个简单的 JSON 文件。你可以手动创建它,但最推荐的方式是在你的项目根目录下运行以下命令:

bash
tsc --init

这个命令会生成一个 tsconfig.json 文件,其中包含了所有可用的配置选项,并且大部分都被注释掉了,附带有详细的说明。这个生成的文件本身就是一份极佳的学习文档。

核心结构:compilerOptions

tsconfig.json 的核心是 compilerOptions 对象。这里定义了 TypeScript 编译过程中的所有规则和行为。让我们来剖析其中最关键的几个选项。

1. 项目输出配置 (The "What" and "Where")

  • target: 指定编译后生成的 JavaScript 版本。

    • 作用:这是最重要的选项之一。它决定了你的代码能在多旧的运行环境中运行。
    • 示例"target": "ES2020" 意味着 TypeScript 会将代码转换为符合 ES2020 规范的 JavaScript。如果你需要支持旧版浏览器,可能会使用 "ES5"
  • module: 指定生成的代码使用哪种模块系统。

    • 作用:决定了代码如何被组织和加载。
    • 示例
      • "CommonJS": 适用于旧版的 Node.js 环境。
      • "ESNext""NodeNext": 适用于现代 Node.js 和支持 ES 模块的前端项目。
  • outDir: 指定编译后生成的 .js 文件存放的目录。

    • 作用:保持项目结构的整洁,将源码和编译产物分离开。
    • 示例"outDir": "./dist" 是一个非常普遍的做法,将所有输出文件放入 dist (distribution) 文件夹。
  • rootDir: 指定 TypeScript 源码文件的根目录。

    • 作用:通常与 outDir 配合使用,以维持 outDir 内的目录结构与 rootDir 一致。
    • 示例"rootDir": "./src" 表示所有源码都在 src 文件夹下。

2. 严格性与质量控制 (The "How Strict")

  • strict: 这是一个“总开关”,开启它等于开启了所有严格类型检查的选项。
    • 作用:强烈推荐始终设置为 true。它能最大限度地发挥 TypeScript 的类型安全优势。
    • 它包含以下关键选项
      • noImplicitAny: 当 TypeScript 无法推断一个变量的类型且你没有显式注解时,会报错。这能消灭代码中所有不明确的 any 类型。
      • strictNullChecks: 严格区分 nullundefined。变量在被赋值前不能被使用,你必须显式地处理可能为 nullundefined 的情况。这是避免 "cannot read property '...' of undefined" 错误的神器。
      • strictFunctionTypes: 更严格地检查函数参数的协变与逆变。
      • strictPropertyInitialization: 确保类中的每个属性都在构造函数中被正确初始化。

3. 模块解析与互操作性

  • moduleResolution: 告诉编译器如何查找模块。

    • 作用:模拟不同模块解析器的行为。
    • 示例"Node"(或现代的 "NodeNext")是绝大多数项目的选择,它模拟了 Node.js 的模块解析策略(查找 node_modules 等)。
  • esModuleInterop: 启用 ES 模块与 CommonJS 模块之间的互操作性。

    • 作用:解决了 import express from 'express'const express = require('express') 之间的差异。强烈建议始终设置为 true,可以避免大量与导入 CommonJS 模块相关的头痛问题。
  • allowJs: 允许在项目中混合使用 .ts.js 文件。

    • 作用:对于从 JavaScript 项目逐步迁移到 TypeScript 的场景非常有用。

4. 调试与环境

  • sourceMap: 生成 .js.map 文件。

    • 作用:这是调试的生命线。它建立了编译后的 .js 文件与原始 .ts 源码之间的映射关系,让你可以在浏览器的开发者工具中直接调试你的 TypeScript 代码。强烈建议始终设置为 true
  • lib: 指定项目中可用的“库”定义文件。

    • 作用:告诉 TypeScript 你的代码运行在什么环境中。例如,如果你在浏览器中运行代码,你需要 DOM 库来识别 documentwindow 等对象。
    • 示例"lib": ["DOM", "DOM.Iterable", "ESNext"] 是现代前端项目的常见配置。

顶层配置:文件范围

除了 compilerOptionstsconfig.json 的顶层还有几个重要的属性,用于定义项目的“边界”。

  • include: 一个数组,指定了需要被编译器包含的文件或目录的模式。

    • 示例"include": ["src/**/*"] 会包含 src 目录下的所有文件。
  • exclude: 一个数组,指定了需要从编译中排除的文件或目录的模式。

    • 作用:通常用于排除测试文件、构建脚本等。
    • 注意node_modules 默认总是被排除的。
    • 示例"exclude": ["node_modules", "**/*.spec.ts"]
  • files: 一个数组,明确列出需要编译的单个文件。这在项目非常小时可能有用,但通常 include 更为灵活。

实践范例:一个现代 Node.js 项目的 tsconfig.json

json
{
  "compilerOptions": {
    /* --- 基本选项 --- */
    "target": "ES2022",           // 编译到现代的 JavaScript 版本
    "module": "NodeNext",        // 使用最新的 Node.js 模块系统
    "lib": ["ES2022"],             // 包含 ES2022 的内置库

    /* --- 严格性 --- */
    "strict": true,                // 开启所有严格检查,保证代码质量
    "skipLibCheck": true,          // 跳过对 .d.ts 声明文件的检查,加快编译速度

    /* --- 模块解析 --- */
    "moduleResolution": "NodeNext", // 使用最新的 Node.js 模块解析策略
    "esModuleInterop": true,       // 启用 CJS 和 ESM 的互操作性

    /* --- 输出 --- */
    "outDir": "./dist",            // 输出目录
    "rootDir": "./src",            // 源码根目录

    /* --- 调试 --- */
    "sourceMap": true              // 生成 Source Map 用于调试
  },
  "include": ["src/**/*"],         // 只编译 src 目录下的文件
  "exclude": ["node_modules"]      // 排除 node_modules
}

总结

tsconfig.json 远不止是一个配置文件,它是你与 TypeScript 编译器沟通的桥梁,是你项目架构的声明。一个深思熟虑的配置能够:

  • 保证代码质量:通过 strict 模式捕获大量潜在错误。
  • 提升开发体验:通过 sourceMap 和正确的模块解析简化调试。
  • 确保兼容性:通过 targetmodule 保证代码在目标环境中正确运行。
  • 保持项目整洁:通过 outDirrootDir 分离源码与产物。

花时间去理解并精心配置你的 tsconfig.json,是每一个 TypeScript 开发者都应该投入的、回报率极高的投资。

不知道说啥了很无语了