返回首页

说说 TypeScript 中的 tsconfig.json 配置?

问题解析

tsconfig.json 是 TypeScript 项目的核心配置文件,考察候选人对编译选项、项目配置、严格模式等关键配置项的理解。

核心概念

  • tsconfig.json:TypeScript 项目配置文件
  • compilerOptions:编译器选项
  • include/exclude:指定包含/排除的文件
  • 严格模式:一系列类型检查严格选项
  • 模块解析:模块查找策略配置

详细解答

1. 基础配置结构

{
  "compilerOptions": {
    // 编译选项
  },
  "include": [
    // 包含的文件
  ],
  "exclude": [
    // 排除的文件
  ],
  "extends": "./base.json",  // 继承其他配置
  "files": [
    // 明确指定的文件
  ]
}

2. 核心编译选项

2.1 基础选项

{
  "compilerOptions": {
    "target": "ES2020",           // 编译目标 JavaScript 版本
    "module": "ESNext",           // 模块系统
    "lib": ["ES2020", "DOM"],     // 包含的库定义文件
    "outDir": "./dist",           // 输出目录
    "rootDir": "./src",           // 源码根目录
    "declaration": true,          // 生成 .d.ts 声明文件
    "sourceMap": true,            // 生成 source map
    "removeComments": true,       // 移除注释
    "noEmit": true                // 不输出文件(仅类型检查)
  }
}

target 可选值ES3ES5ES6/ES2015ES2016ES2017ES2018ES2019ES2020ES2021ES2022ESNext

module 可选值CommonJSAMDSystemUMDES6/ES2015ES2020ES2022ESNextNode16NodeNext

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               // 严格模式
  }
}

strict: true 包含

  • noImplicitAny
  • strictNullChecks
  • strictFunctionTypes
  • strictBindCallApply
  • strictPropertyInitialization
  • noImplicitThis
  • alwaysStrict

2.3 模块解析选项

{
  "compilerOptions": {
    "moduleResolution": "node",        // 模块解析策略
    "baseUrl": ".",                    // 基础路径
    "paths": {                         // 路径映射
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"]
    },
    "rootDirs": ["src", "generated"],  // 虚拟根目录
    "typeRoots": ["./node_modules/@types"],  // 类型定义根目录
    "types": ["node", "jest"],         // 包含的类型定义
    "allowSyntheticDefaultImports": true,  // 允许默认导入
    "esModuleInterop": true            // ES 模块互操作
  }
}

2.4 高级选项

{
  "compilerOptions": {
    "experimentalDecorators": true,    // 启用装饰器
    "emitDecoratorMetadata": true,     // 生成装饰器元数据
    "jsx": "react-jsx",                // JSX 处理方式
    "skipLibCheck": true,              // 跳过库类型检查
    "forceConsistentCasingInFileNames": true,  // 强制文件名大小写一致
    "resolveJsonModule": true,         // 允许导入 JSON
    "isolatedModules": true,           // 确保文件可以独立编译
    "noEmitOnError": true              // 有错误时不输出文件
  }
}

jsx 可选值

  • preserve:保留 JSX 语法
  • react:转换为 React.createElement
  • react-native:保留 JSX 语法
  • react-jsx:转换为新的 JSX 转换(React 17+)
  • react-jsxdev:开发模式的新 JSX 转换

3. 项目配置示例

3.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,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

3.2 React 项目

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["DOM", "DOM.Iterable", "ES2020"],
    "allowJs": false,
    "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",
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src"]
}

3.3 库项目

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    "declaration": true,
    "declarationMap": true,
    "outDir": "./lib",
    "rootDir": "./src",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "lib", "**/*.spec.ts"]
}

4. 配置文件继承

// base.json
{
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

// tsconfig.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext"
  }
}

5. 多配置管理

// tsconfig.json - 主配置
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "noEmit": true
  },
  "include": ["src/**/*"]
}

// tsconfig.build.json - 构建配置
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "declaration": true
  },
  "include": ["src/**/*"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

// tsconfig.node.json - Node 脚本配置
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "module": "CommonJS",
    "outDir": "./scripts/dist"
  },
  "include": ["scripts/**/*"]
}

深入理解

严格模式详解

{
  "compilerOptions": {
    "strict": true
  }
}

等效于:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}

各选项含义

选项 说明
noImplicitAny 禁止隐式 any 类型
strictNullChecks null 和 undefined 只能赋值给自身和 void
strictFunctionTypes 严格函数参数和返回值类型检查
strictBindCallApply 严格检查 bind/call/apply 的参数
strictPropertyInitialization 类属性必须在声明或构造函数中初始化
noImplicitThis 禁止 this 隐式为 any
alwaysStrict 每个文件都使用严格模式

模块解析策略

{
  "compilerOptions": {
    "moduleResolution": "node"
  }
}

Node 策略查找顺序

  1. import { foo } from 'module'
  2. 查找 node_modules/module.ts
  3. 查找 node_modules/module.tsx
  4. 查找 node_modules/module.d.ts
  5. 查找 node_modules/module/package.jsontypes 字段
  6. 查找 node_modules/@types/module.d.ts
  7. 查找 node_modules/module/index.ts

路径映射配置

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

配合构建工具(webpack、vite、rollup)使用:

// 使用路径映射
import { Button } from '@components/Button';
import { formatDate } from '@utils/date';
import type { User } from '@types/user';

最佳实践

  1. 启用严格模式strict: true 获得最佳类型安全
  2. 合理配置 target:根据运行环境选择 JavaScript 版本
  3. 使用路径映射:简化模块导入路径
  4. 分离配置文件:开发、测试、生产使用不同配置
  5. 版本控制:将 tsconfig.json 纳入版本控制
  6. IDE 配合:确保编辑器使用项目配置的 TypeScript 版本

面试要点

  1. 基础选项

    • target:编译目标版本
    • module:模块系统
    • outDir/rootDir:输入输出目录
    • lib:包含的库定义
  2. 严格模式

    • strict: true 启用所有严格检查
    • 包含 noImplicitAnystrictNullChecks
  3. 模块解析

    • moduleResolutionnodeclassic
    • baseUrl + paths:路径映射
    • typeRoots/types:类型定义配置
  4. 高级选项

    • experimentalDecorators:装饰器支持
    • jsx:JSX 处理方式
    • skipLibCheck:跳过库类型检查
    • esModuleInterop:ES 模块互操作
  5. 项目配置

    • include/exclude:文件包含/排除
    • extends:配置继承
    • 多配置文件管理
  6. 常见面试问题

    • strictNullChecks 的作用
    • noImplicitAny 与显式 any 的区别
    • esModuleInterop 解决了什么问题
    • skipLibCheck 的适用场景