Skip to content
On this page

ESLint TypeScript 支持

ESLint 为 TypeScript 提供了强大的支持,本章详细介绍如何配置和使用 ESLint 进行 TypeScript 代码检查。

TypeScript 支持概述

ESLint 通过 @typescript-eslint/parser@typescript-eslint/eslint-plugin 提供对 TypeScript 的支持。

核心包介绍

  • @typescript-eslint/parser: 用于解析 TypeScript 代码的 ESLint 解析器
  • @typescript-eslint/eslint-plugin: 提供 TypeScript 特定规则的 ESLint 插件
  • @typescript-eslint/typescript-estree: 将 TypeScript 代码转换为 ESTree 兼容的 AST

安装 TypeScript 支持

安装核心依赖

bash
# 安装 ESLint 和 TypeScript 支持
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin

# 或者使用 yarn
yarn add --dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin

安装 TypeScript

bash
# 安装 TypeScript
npm install --save-dev typescript

# 或者使用 yarn
yarn add --dev typescript

基础配置

简单 TypeScript 配置

javascript
// .eslintrc.js
module.exports = {
  // 指定解析器为 TypeScript 解析器
  parser: '@typescript-eslint/parser',
  
  // 指定 ESLint 配置的环境
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended'
  ],
  
  // 指定解析器选项
  parserOptions: {
    ecmaVersion: 2021,     // 支持的 ECMAScript 版本
    sourceType: 'module',   // 模块类型
    ecmaFeatures: {
      jsx: true           // 如果使用 TSX
    },
    // TypeScript 特定选项
    project: './tsconfig.json',  // 指定 tsconfig.json 路径
    tsconfigRootDir: __dirname   // tsconfig.json 的根目录
  },
  
  // 使用 TypeScript 插件
  plugins: [
    '@typescript-eslint'
  ],
  
  // 具体规则配置
  rules: {
    // TypeScript 特定规则
    '@typescript-eslint/explicit-function-return-type': 'warn',
    '@typescript-eslint/explicit-module-boundary-types': 'warn',
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/no-unused-vars': 'error'
  }
};

完整的 TypeScript 配置

javascript
// .eslintrc.js
module.exports = {
  // 解析器
  parser: '@typescript-eslint/parser',
  
  // 解析器选项
  parserOptions: {
    ecmaVersion: 2021,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true
    },
    // TypeScript 特定选项
    project: './tsconfig.json',      // 启用类型检查
    tsconfigRootDir: __dirname,
    warnOnUnsupportedTypeScriptVersion: true
  },
  
  // 继承的配置
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    '@typescript-eslint/recommended-requiring-type-checking',
    'plugin:import/recommended',
    'plugin:import/typescript'
  ],
  
  // 使用的插件
  plugins: [
    '@typescript-eslint',
    'import'
  ],
  
  // 设置
  settings: {
    'import/resolver': {
      typescript: {
        project: './tsconfig.json'
      }
    }
  },
  
  // 规则配置
  rules: {
    // 基础规则
    'no-console': 'warn',
    'no-debugger': 'error',
    
    // TypeScript 特定规则
    '@typescript-eslint/explicit-function-return-type': 'off',  // 不强制要求返回类型
    '@typescript-eslint/explicit-module-boundary-types': 'off', // 不强制要求边界类型
    '@typescript-eslint/no-explicit-any': 'warn',              // 允许 any,但警告
    '@typescript-eslint/no-unused-vars': ['error', { 
      'argsIgnorePattern': '^_',  // 忽略以 _ 开头的参数
      'varsIgnorePattern': '^_'   // 忽略以 _ 开头的变量
    }],
    '@typescript-eslint/no-inferrable-types': 'warn',          // 不允许可推断的类型定义
    '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], // 优先使用 interface
    '@typescript-eslint/prefer-const': 'error',
    '@typescript-eslint/no-var-requires': 'error',
    '@typescript-eslint/explicit-member-accessibility': ['error', { 'accessibility': 'no-public' }], // 成员可访问性
    '@typescript-eslint/naming-convention': [                  // 命名约定
      'error',
      {
        selector: 'variableLike',
        format: ['camelCase', 'UPPER_CASE']
      },
      {
        selector: 'typeLike',
        format: ['PascalCase']
      }
    ]
  }
};

TypeScript 特定规则详解

类型相关规则

javascript
module.exports = {
  rules: {
    // 显式函数返回类型
    '@typescript-eslint/explicit-function-return-type': [
      'warn',
      {
        'allowExpressions': true,                    // 允许表达式
        'allowTypedFunctionExpressions': true,      // 允许类型化的函数表达式
        'allowHigherOrderFunctions': true,          // 允许高阶函数
        'allowDirectConstAssertionInArrowFunctions': true, // 允许箭头函数中的直接常量断言
        'allowConciseArrowFunctionExpressionsStartingWithVoid': false // 不允许以 void 开头的简洁箭头函数
      }
    ],
    
    // 显式模块边界类型
    '@typescript-eslint/explicit-module-boundary-types': [
      'warn',
      {
        'allowArgumentsExplicitlyTypedAsAny': false,  // 不允许参数显式声明为 any
        'allowDirectConstAssertionInArrowFunctions': true, // 允许箭头函数中的直接常量断言
        'allowedNames': [],                         // 允许的函数名
        'shouldTrackReferences': true               // 应该跟踪引用
      }
    ],
    
    // 不允许显式的 any 类型
    '@typescript-eslint/no-explicit-any': [
      'warn',
      {
        'fixToUnknown': false,                     // 不自动修复为 unknown
        'ignoreRestArgs': true                     // 忽略 rest 参数
      }
    ],
    
    // 不允许不安全的类型断言
    '@typescript-eslint/consistent-type-assertions': [
      'error',
      {
        'assertionStyle': 'as',                    // 使用 as 语法
        'objectLiteralTypeAssertions': 'allow'     // 允许对象字面量类型断言
      }
    ],
    
    // 一致的类型定义
    '@typescript-eslint/consistent-type-definitions': [
      'error',
      'interface'  // 优先使用 interface 而不是 type
    ],
    
    // 不允许空接口
    '@typescript-eslint/no-empty-interface': [
      'error',
      {
        'allowSingleExtends': true  // 允许单继承
      }
    ],
    
    // 不允许不安全的解构
    '@typescript-eslint/no-unsafe-assignment': 'error',
    '@typescript-eslint/no-unsafe-member-access': 'error',
    '@typescript-eslint/no-unsafe-call': 'error',
    '@typescript-eslint/no-unsafe-return': 'error'
  }
};

命名约定规则

javascript
module.exports = {
  rules: {
    // 命名约定
    '@typescript-eslint/naming-convention': [
      'error',
      // 变量和函数使用 camelCase
      {
        selector: 'variableLike',
        format: ['camelCase', 'UPPER_CASE'],
        leadingUnderscore: 'allow',
        trailingUnderscore: 'allow'
      },
      // 类型和接口使用 PascalCase
      {
        selector: 'typeLike',
        format: ['PascalCase']
      },
      // 枚举成员使用 PascalCase 或 UPPER_CASE
      {
        selector: 'enumMember',
        format: ['PascalCase', 'UPPER_CASE']
      },
      // 方法使用 camelCase
      {
        selector: 'method',
        format: ['camelCase'],
        leadingUnderscore: 'allow'
      },
      // 类和接口使用 PascalCase
      {
        selector: 'class',
        format: ['PascalCase']
      },
      // 泛型类型参数使用 PascalCase,通常以 T 或字母开头
      {
        selector: 'typeParameter',
        format: ['PascalCase'],
        prefix: ['T', 'K']
      }
    ]
  }
};

项目引用配置

tsconfig.json 配置

json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

ESLint 与 TypeScript 项目配置

javascript
// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',  // 指定 TypeScript 配置文件
    tsconfigRootDir: __dirname,
    ecmaVersion: 2021,
    sourceType: 'module'
  },
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    '@typescript-eslint/recommended-requiring-type-checking'  // 需要类型检查的规则
  ],
  plugins: [
    '@typescript-eslint'
  ],
  rules: {
    // 需要类型检查的规则
    '@typescript-eslint/restrict-plus-operands': 'error',  // 限制 + 操作符的使用
    '@typescript-eslint/prefer-string-starts-ends-with': 'error',  // 优先使用 startsWith/endsWith
    '@typescript-eslint/no-floating-promises': 'error',    // 不允许浮动的 Promise
    '@typescript-eslint/await-thenable': 'error',         // await 后面必须是 thenable
    '@typescript-eslint/prefer-includes': 'error',        // 优先使用 includes 而不是 indexOf
    '@typescript-eslint/no-for-in-array': 'error',        // 不允许在数组上使用 for-in
    '@typescript-eslint/prefer-regexp-exec': 'error',     // 优先使用 RegExp.exec 而不是 String.match
    '@typescript-eslint/no-implied-eval': 'error',        // 不允许隐式 eval
    '@typescript-eslint/prefer-namespace-keyword': 'error', // 优先使用 namespace 关键字
    '@typescript-eslint/no-unnecessary-type-assertion': 'error', // 不允许不必要的类型断言
    '@typescript-eslint/prefer-for-of': 'error',          // 优先使用 for-of 循环
    '@typescript-eslint/prefer-function-type': 'error',   // 优先使用函数类型
    '@typescript-eslint/no-array-constructor': 'error',   // 不允许使用 Array 构造函数
    '@typescript-eslint/no-extra-semi': 'error',          // 不允许额外的分号
    '@typescript-eslint/no-misused-new': 'error',         // 防止错误使用 new
    '@typescript-eslint/no-namespace': 'error',           // 不允许命名空间
    '@typescript-eslint/no-non-null-assertion': 'warn',   // 不允许非空断言(警告)
    '@typescript-eslint/no-this-alias': 'error',          // 不允许 this 别名
    '@typescript-eslint/no-unnecessary-qualifier': 'error', // 不允许不必要的限定符
    '@typescript-eslint/no-unnecessary-type-arguments': 'error', // 不允许不必要的类型参数
    '@typescript-eslint/no-useless-constructor': 'error',  // 不允许无用的构造函数
    '@typescript-eslint/prefer-readonly': 'error',        // 优先使用 readonly
    '@typescript-eslint/promise-function-async': 'error',  // Promise 函数应为 async
    '@typescript-eslint/require-array-sort-compare': 'error', // 数组排序需要比较函数
    '@typescript-eslint/restrict-template-expressions': 'error', // 限制模板表达式
    '@typescript-eslint/switch-exhaustiveness-check': 'error', // switch 语句完整性检查
    '@typescript-eslint/unbound-method': 'error'          // 方法绑定检查
  }
};

React 与 TypeScript 集成

React + TypeScript 配置

javascript
// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    },
    project: './tsconfig.json'
  },
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    '@typescript-eslint/recommended-requiring-type-checking',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:import/recommended',
    'plugin:import/typescript'
  ],
  plugins: [
    'react',
    '@typescript-eslint',
    'import'
  ],
  settings: {
    react: {
      version: 'detect'
    },
    'import/resolver': {
      typescript: {
        project: './tsconfig.json'
      }
    }
  },
  rules: {
    // React 特定规则
    'react/react-in-jsx-scope': 'off',  // React 17+ 不需要导入
    'react/prop-types': 'off',          // TypeScript 提供类型检查
    
    // TypeScript 特定规则
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/no-unused-vars': ['error', { 
      'argsIgnorePattern': '^_',
      'varsIgnorePattern': '^_'
    }],
    
    // Import 规则
    'import/order': [
      'error',
      {
        groups: [
          'builtin',      // 内置模块
          'external',     // 外部模块
          'internal',     // 内部模块
          'parent',       // 父目录
          'sibling',      // 同级目录
          'index',        // 索引文件
          'object'        // 对象导入
        ],
        'newlines-between': 'always',
        alphabetize: {
          order: 'asc',
          caseInsensitive: true
        }
      }
    ]
  }
};

高级 TypeScript 配置

多项目配置

javascript
// .eslintrc.js
module.exports = {
  // 通用配置
  parser: '@typescript-eslint/parser',
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended'
  ],
  plugins: [
    '@typescript-eslint'
  ],
  
  // 覆盖配置
  overrides: [
    // 主应用配置
    {
      files: ['src/**/*.{ts,tsx}'],
      parserOptions: {
        project: './tsconfig.json'
      },
      extends: [
        '@typescript-eslint/recommended',
        '@typescript-eslint/recommended-requiring-type-checking'
      ],
      rules: {
        '@typescript-eslint/no-explicit-any': 'error'
      }
    },
    
    // 测试文件配置
    {
      files: ['**/*.{test,spec}.{ts,tsx}'],
      parserOptions: {
        project: './tsconfig.json'
      },
      env: {
        jest: true
      },
      plugins: [
        'jest'
      ],
      extends: [
        'plugin:jest/recommended'
      ],
      rules: {
        '@typescript-eslint/no-explicit-any': 'off',  // 测试文件中允许 any
        '@typescript-eslint/no-non-null-assertion': 'off', // 测试文件中允许非空断言
        'jest/expect-expect': 'off'
      }
    },
    
    // 配置文件配置
    {
      files: ['*.config.ts', '*.conf.ts'],
      rules: {
        '@typescript-eslint/no-var-requires': 'off',
        '@typescript-eslint/no-require-imports': 'off'
      }
    }
  ]
};

严格类型检查配置

javascript
// .eslintrc.strict.js
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json'
  },
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    '@typescript-eslint/recommended-requiring-type-checking',
    '@typescript-eslint/strict'  // 严格模式
  ],
  plugins: [
    '@typescript-eslint'
  ],
  rules: {
    // 严格模式规则
    '@typescript-eslint/no-explicit-any': 'error',           // 不允许 any
    '@typescript-eslint/no-non-null-assertion': 'error',    // 不允许非空断言
    '@typescript-eslint/strict-boolean-expressions': 'error', // 严格布尔表达式
    '@typescript-eslint/restrict-plus-operands': 'error',   // 限制 + 操作符
    '@typescript-eslint/prefer-nullish-coalescing': 'error', // 优先使用空值合并
    '@typescript-eslint/prefer-optional-chain': 'error',     // 优先使用可选链
    '@typescript-eslint/prefer-reduce-type-parameter': 'error', // 优先使用 reduce 类型参数
    '@typescript-eslint/prefer-return-this-type': 'error',   // 优先返回 this 类型
    '@typescript-eslint/require-array-sort-compare': 'error', // 数组排序需要比较函数
    '@typescript-eslint/restrict-template-expressions': 'error', // 限制模板表达式
    '@typescript-eslint/switch-exhaustiveness-check': 'error', // switch 完整性检查
    '@typescript-eslint/unified-signatures': 'error',        // 统一签名
    '@typescript-eslint/no-base-to-string': 'error',        // 防止基础类型转字符串
    '@typescript-eslint/no-duplicate-enum-values': 'error', // 不允许重复枚举值
    '@typescript-eslint/no-duplicate-type-constituents': 'error', // 不允许重复类型成分
    '@typescript-eslint/no-meaningless-void-operator': 'error', // 不允许无意义的 void 操作符
    '@typescript-eslint/no-misused-promises': 'error',      // 防止错误使用 Promise
    '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error', // 不允许不必要的布尔字面量比较
    '@typescript-eslint/no-unnecessary-condition': 'error',  // 不允许不必要的条件
    '@typescript-eslint/no-unnecessary-qualifier': 'error',  // 不允许不必要的限定符
    '@typescript-eslint/no-unnecessary-type-arguments': 'error', // 不允许不必要的类型参数
    '@typescript-eslint/no-unnecessary-type-assertion': 'error', // 不允许不必要的类型断言
    '@typescript-eslint/no-unsafe-argument': 'error',       // 不允许不安全的参数
    '@typescript-eslint/no-unsafe-assignment': 'error',     // 不允许不安全的赋值
    '@typescript-eslint/no-unsafe-call': 'error',          // 不允许不安全的调用
    '@typescript-eslint/no-unsafe-member-access': 'error',  // 不允许不安全的成员访问
    '@typescript-eslint/no-unsafe-return': 'error',        // 不允许不安全的返回
    '@typescript-eslint/non-nullable-type-assertion-style': 'error', // 非空类型断言风格
    '@typescript-eslint/prefer-as-const': 'error',         // 优先使用 as const
    '@typescript-eslint/prefer-find': 'error',             // 优先使用 find
    '@typescript-eslint/prefer-for-of': 'error',           // 优先使用 for-of
    '@typescript-eslint/prefer-includes': 'error',         // 优先使用 includes
    '@typescript-eslint/prefer-literal-enum-member': 'error', // 优先使用字面量枚举成员
    '@typescript-eslint/prefer-readonly': 'error',         // 优先使用 readonly
    '@typescript-eslint/prefer-readonly-parameter-types': 'warn', // 优先使用 readonly 参数类型
    '@typescript-eslint/prefer-reduce': 'error',           // 优先使用 reduce
    '@typescript-eslint/prefer-regexp-exec': 'error',      // 优先使用 RegExp.exec
    '@typescript-eslint/prefer-string-starts-ends-with': 'error', // 优先使用 startsWith/endsWith
    '@typescript-eslint/promise-function-async': 'error',   // Promise 函数应为 async
    '@typescript-eslint/require-await': 'error',           // 需要 await
    '@typescript-eslint/restrict-array-constructors': 'error', // 限制数组构造函数
    '@typescript-eslint/restrict-template-expressions': [
      'error',
      {
        'allowNumber': true,
        'allowBoolean': true,
        'allowAny': false,
        'allowNullish': true,
        'allowRegExp': false
      }
    ]
  }
};

性能优化

TypeScript 检查优化

javascript
// .eslintrc.js - 性能优化配置
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
    tsconfigRootDir: __dirname,
    
    // 性能优化选项
    warnOnUnsupportedTypeScriptVersion: true,
    allowAutomaticSingleRunInference: true  // 允许自动单次运行推断
  },
  
  // 启用缓存
  cache: true,
  cacheLocation: '.eslintcache',
  
  // 排除不需要检查的文件
  ignorePatterns: [
    'node_modules/',
    'dist/',
    'build/',
    '*.min.js',
    'coverage/',
    '.next/',
    '.nuxt/',
    '*.d.ts'
  ],
  
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended'
  ],
  
  plugins: [
    '@typescript-eslint'
  ],
  
  // 在开发环境中只检查修改的文件
  // 在 CI/CD 环境中检查所有文件
  rules: {
    // 性能密集型规则可以关闭或调整
    '@typescript-eslint/strict-boolean-expressions': 'off',  // 在开发环境中关闭
    '@typescript-eslint/no-unnecessary-condition': 'off',    // 在开发环境中关闭
    '@typescript-eslint/no-unnecessary-type-assertion': 'off' // 在开发环境中关闭
  }
};

故障排除

常见问题及解决方案

bash
# 问题1: "Parsing error: Cannot read properties of undefined (reading 'name')"
# 解决方案: 确保正确安装并配置 TypeScript
npm install --save-dev typescript

# 问题2: "The file does not match your project config"
# 解决方案: 检查 tsconfig.json 配置
# 确保文件包含在 include 中或不在 exclude 中

# 问题3: "Parsing error: Cannot find module '@typescript-eslint/parser'"
# 解决方案: 重新安装依赖
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin

# 问题4: 性能问题
# 解决方案: 启用缓存
npx eslint --cache --cache-location .eslintcache src/

TypeScript 版本兼容性

javascript
// 检查 TypeScript 版本兼容性
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
    tsconfigRootDir: __dirname,
    warnOnUnsupportedTypeScriptVersion: true  // 警告不支持的 TypeScript 版本
  },
  
  // 根据 TypeScript 版本启用不同的规则
  rules: {
    // 较新版本的 TypeScript 支持的规则
    '@typescript-eslint/prefer-for-of': 'error',
    '@typescript-eslint/prefer-includes': 'error'
  }
};

小结

ESLint 的 TypeScript 支持非常强大,通过正确的配置可以实现全面的类型安全检查。关键是要正确安装和配置 @typescript-eslint/parser@typescript-eslint/eslint-plugin,并根据项目需求选择合适的规则。合理的配置不仅能提高代码质量,还能提升开发体验。