react/react-in-jsx-scope
当使用 JSX 语法时,React 必须在作用域内(即需要显式导入 React)。
在 React 17 之前,每次使用 JSX 语法时,Babel 会将其转换为 React.createElement() 调用,因此必须导入 React 才能使用 JSX。
举例
index.jsx
javascript
export default () => <div>New Page index</div>;
应修改为
javascript
import React from 'react';
export default () => <div>New Page index</div>;
max-len
eslint默认最大行长度为100
处理方法:修改eslint配置项
.eslintrc.js
javascript
const { strictEslint } = require('@umijs/fabric');
module.exports = {
...strictEslint,
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
page: true,
},
rules: {
...strictEslint.rules,
'max-len': ['error', {
code: 100, // 最大行长度
ignoreComments: true, // 忽略注释行
ignoreStrings: true, // 忽略字符串字面量(避免因长 URL 或模板字符串报错)
ignoreTemplateLiterals: true, // 忽略模板字符串
ignoreRegExpLiterals: true, // 忽略正则表达式
ignoreUrls: true, // 忽略 URL
}],
},
}
注意:如果注释行为JSX注释,将不被eslint视为注释行
在 ESLint 的 max-len 规则中, ignoreComments: true 只适用于 真正的注释 :
- // 单行注释
- /* 多行注释 */
而 JSX 中的 {/* ... */} 虽然在语义上是注释,但在 AST(抽象语法树)中,它被解析为:
- { - JSX 表达式开始
- /* ... */ - 内部的注释
- } - JSX 表达式结束
因此,ESLint 的 max-len 规则 不将 JSX 注释视为纯注释行 ,仍然会检查其长度。
举例
javascript
const SubmitFormItem = ({ className, ...rest }) => {
const clsString = classNames(styles.submit, className);
return (
<FormItem>
{/* <Button size="large" className={clsString} type="primary" htmlType="submit" {...rest} /> */}
<Button size="large" className={clsString} htmlType="submit" {...rest} />
</FormItem>
);
};
template literals
ESLint 推荐使用模板字符串(template literals)而不是字符串拼接。
javascript
const title={`添加${title}`} // 模态框标题
Parsing error: Expression expected.
javascript
const page = service?.data?.page || {};
在老旧项目中,可选链操作符(``?.`` )是ES2020的特性,可能ESLint的解析器配置没有正确支持这个语法。
修改配置项,添加ES2020的特性支持
.eslintrc.js
javascript
const { strictEslint } = require('@umijs/fabric');
module.exports = {
...strictEslint,
rules: {
...
},
overrides: [
{
files: ['*.js', '*.jsx'],
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2020,
ecmaFeatures: {
jsx: true,
},
},
},
],
};
这样,当执行 npm run lint 命令时,就不会再因为可选链操作符而报错了
变量 is defined but never used
方法1:使用ESLint自动修复
bash
# 自动修复所有可修复的问题,包括未使用的变量
npx eslint --fix src/
# 或者使用 yarn
yarn eslint --fix src/
# 或者 npm
npm run lint:fix
注意: 以下未使用对象需手动删除,ESLint 无法确定是否真的不需要
- 未使用的导入
- 未使用的函数变量
解决方案: 手动删除、使用代码清理工具
方法2:使用代码清理工具
eslint-plugin-unused-imports :专门用于检测和移除未使用的导入
安装插件
bash
# 使用 npm
npm install --save-dev eslint-plugin-unused-imports @typescript-eslint/eslint-plugin @typescript-eslint/parser
# 或使用 yarn
yarn add --dev eslint-plugin-unused-imports @typescript-eslint/eslint-plugin @typescript-eslint/parser
配置.eslintrc.js
javascript
module.exports = {
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
'unused-imports' // 添加插件
],
rules: {
// 配置未使用导入的规则
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
'error',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_'
}
],
// 其他规则...
}
};
运行 以下命令来自动修复未使用的导入
bash
# 自动修复所有可修复的问题
npx eslint --fix src/
# 或使用 yarn
yarn eslint --fix src/
集成到开发流程
可以将 ESLint 检查添加到项目的 package.json 脚本中:
bash
"scripts": {
"lint": "eslint src/",
"lint:fix": "eslint --fix src/"
}
方法3:修改ESLint配置(不推荐)
可能导致代码质量下降
配置规则为警告而非错误
javascript
rules: {
...strictEslint.rules,
'eqeqeq': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
}
或者
允许忽略特定模式的未使用变量
javascript
module.exports = {
...strictEslint,
rules: {
...strictEslint.rules,
'@typescript-eslint/no-unused-vars': ['warn', {
vars: 'all',
varsIgnorePattern: '^_|^React$', // 忽略 React 和以 _ 开头的变量
args: 'after-used',
argsIgnorePattern: '^_'
}],
},
};
^_ - 忽略以 _ 开头的变量(如 _unused )
^React$ - 忽略 React(因为 JSX 需要)
Unary operator ++ used
意思是禁止使用自增运算符 ++(例如 i++ 或 ++i)
1. 为什么会有这个规则?
这条规则通常出现在追求函数式编程风格 或代码绝对清晰的项目中(如 Airbnb 风格指南)。主要理由包括:
- 隐式副作用 :
i++不仅返回值,还修改变量i。在某些复杂的表达式中(如array[i++] = i),这可能导致代码难以阅读且容易出错。 - 自动分号插入问题 :在某些极端情况下,
++紧跟在行尾可能会引起解析歧义(虽然现代工具处理得很好,但这是一个历史遗留顾虑)。 - 鼓励显式操作 :强制开发者写出更明确的意图,比如
i += 1。
2. 如何解决?
配置.eslintrc.js
javascript
'no-plusplus': 'off',
或者
javascript
// 显式加 1
i += 1;
// 在循环中
for (let i = 0; i < len; i += 1) {
// ...
}
no-nested-ternary
不允许嵌套多个三元运算符,代码阅读不友好
可以改为if else
no-underscore-dangle
在代码中使用了以下划线 _ 开头或结尾的标识符(variable/property name),这违反了 ESLint 的 no-underscore-dangle 规则。
no-constant-condition
禁止在控制流语句(如 if、while、for、条件运算符 ?:)中使用常量表达式作为条件。
javascript
// 1. 典型的错误写法
if (a = 5) { // 报错:这是一个赋值表达式,结果永远是 5 (truthy),意图可能是 a == 5
// ...
}
// 2. 逻辑运算结果恒定
if (foo || true) { // 报错:无论 foo 是什么,结果永远为真
// ...
}
// 3. 三元运算符中的常量
var a = true ? 'foo' : 'bar'; // 报错:条件恒定为真,'bar' 永远无法执行
为什么要有这条规则?
- 防止死循环 :
while (true)如果没有内部的break,会导致程序卡死。虽然有时故意写while(true),但 ESLint 希望你显式地关闭该规则或使用注释说明。 - 发现拼写错误 :最常见的是把比较运算符
==或===误写成了赋值运算符=。例如if (x = 5)实际上是将 5 赋值给 x,然后判断 5(真),这通常不是开发者的本意。 - 移除死代码 :如果条件是
if (false),那么里面的代码永远不会执行,这是无用代码。
array-callback-return
map() 方法期望回调函数 返回一个值 来构成新数组,但这里的回调函数没有 return 语句
将map修改为forEach
no-shadow(变量遮蔽)
禁止变量声明遮蔽(Shadowing)外部作用域中已存在的变量。
变量遮蔽: 当一个内部作用域(如函数内部、代码块内部)声明了一个与外部作用域同名 的变量时,内部变量就会"遮蔽"外部变量。在内部作用域中,如果你使用该变量名,访问到的将是内部变量,而外部变量变得不可访问。
javascript
let message = "Hello";
function printMessage(message) { // 报错:参数 'message' 遮蔽了外部的 'message'
console.log(message); // 这里打印的是参数,而不是外部的 "Hello"
}
为什么 ESLint 要禁止它?
- 代码可读性差 :阅读代码时,很难分清当前使用的是内部变量还是外部变量,容易造成混淆。
- 潜在的逻辑错误 :开发者可能本意是想修改外部变量,结果不小心声明了一个新的局部变量,导致外部变量未被更新,引发难以察觉的 Bug。
- 维护困难 :当代码嵌套层级较深时,追踪变量的来源变得非常困难。
no-empty-pattern
禁止在解构赋值(Destructuring Assignment)中使用空的对象模式或空的数组模式。
这条规则防止你写出像
javascript
// 1. 空对象解构
const {} = foo; // 报错:Unexpected empty object pattern
// 2. 空数组解构
const [] = bar; // 报错:Unexpected empty array pattern
// 3. 函数参数中的空解构
function process({}) { // 报错
// ...
}
// 4. 嵌套中的空解构
const { a: {} } = data; // 报错:a 对应的值是空对象模式
这样的代码。这种写法在 JavaScript 中虽然语法合法,但通常没有任何实际意义(它不会提取任何变量,也不会报错,只是单纯地"路过"了一下数据),往往是复制粘贴错误 或逻辑遗漏导致的。
javascript
const { a: {} } = data;
在上述代码中,如果 a 不存在,你想让它默认为一个空对象 {}
javascript
// ✅ 正确写法:如果 data.a 是 undefined,则 obj 默认为 {}
const { a: obj = {} } = data;
console.log(obj); // 如果 data 中没有 a,这里输出 {}
或者,如果 a 不存在,你只想忽略它,不需要任何变量
javascript
// ✅ 正确写法:只提取 a,不做嵌套匹配
const { a } = data;
// 或者如果你连变量 a 都不想要,可以直接忽略
// (这种写法通常没必要,除非是为了触发某些副作用,但一般直接不写就行)
或者,如果 a 存在,你想从 a 里面提取具体的属性(比如 name)
javascript
// ✅ 正确写法:嵌套解构 + 默认值
// 含义:从 data 中找 a,如果 a 不存在,视为 {},然后从结果中找 name,如果 name 也不存在,默认为 'Unknown'
const { a: { name = 'Unknown' } = {} } = data;
console.log(name);
// 情况 A: data = { a: { name: 'Alice' } } -> 输出 'Alice'
// 情况 B: data = { a: {} } -> 输出 'Unknown'
// 情况 C: data = {} -> 输出 'Unknown' (因为 a 缺失,用了默认值 {})
| 意图 | ❌ 错误写法 (会报错/崩溃) | ✅ 正确写法 |
|---|---|---|
| 给默认空对象 | const { a: {} } = data; |
const { a: obj = {} } = data; |
| 提取内部属性 | const { a: { name } } = data; (若 a 缺失则崩溃) |
const { a: { name } = {} } = data; |
| 仅仅检查/忽略 | const { a: {} } = data; |
const { a } = data; |