Appearance
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,并根据项目需求选择合适的规则。合理的配置不仅能提高代码质量,还能提升开发体验。