代码质量标准与 Lint 规范
AI 生成的代码在风格上可能与团队现有代码库存在差异——变量命名不一致、函数过长、复杂度过高、格式混乱。制定并强制执行统一的 Lint 规范,是将 AI 生成代码纳入可维护代码库的关键步骤。
为什么需要专门针对 AI 代码制定质量规范
AI 模型生成代码时,会根据上下文推断风格,但不了解项目的具体约定。常见问题包括:
- 风格漂移:生成的代码与文件其他部分缩进、引号风格不一致
- 过度工程化:为简单功能生成多层抽象,增加认知负担
- 命名模糊:使用
data、result、temp等无意义变量名 - 注释冗余:大量解释"做了什么"的注释,而非解释"为什么"
ESLint 推荐配置
以下是适用于 TypeScript + React 项目的完整 ESLint 配置,针对 AI 生成代码的常见问题加入了额外规则:
javascript
// eslint.config.js (ESLint v9 flat config)
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import sonarjs from 'eslint-plugin-sonarjs';
import unicorn from 'eslint-plugin-unicorn';
export default [
js.configs.recommended,
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: './tsconfig.json',
},
},
plugins: {
'@typescript-eslint': typescript,
react,
'react-hooks': reactHooks,
sonarjs,
unicorn,
},
rules: {
// --- TypeScript 严格规则 ---
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
// --- 复杂度控制(针对 AI 过度生成) ---
'complexity': ['error', { max: 10 }],
'max-lines-per-function': ['warn', { max: 50, skipComments: true }],
'max-depth': ['error', 4],
'max-params': ['warn', 4],
// --- SonarJS 代码质量规则 ---
'sonarjs/cognitive-complexity': ['error', 15],
'sonarjs/no-duplicate-string': ['warn', { threshold: 3 }],
'sonarjs/no-identical-functions': 'error',
'sonarjs/no-redundant-boolean': 'error',
// --- 命名规范 ---
'unicorn/prevent-abbreviations': ['warn', {
replacements: {
res: { response: true },
req: { request: true },
err: { error: true },
cb: { callback: true },
},
}],
// --- React 规则 ---
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'react/no-array-index-key': 'warn',
},
},
];Prettier 配置
格式化应完全交给 Prettier,ESLint 只负责代码质量,不负责风格:
json
// .prettierrc
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf"
}json
// .prettierignore
dist/
build/
coverage/
*.min.js将 Prettier 集成到 ESLint(避免规则冲突):
bash
npm install -D eslint-config-prettierjavascript
// eslint.config.js 末尾添加
import prettierConfig from 'eslint-config-prettier';
export default [
// ...前面的配置
prettierConfig, // 必须放最后,禁用与 Prettier 冲突的规则
];命名约定规范
| 类型 | 规范 | 示例 |
|---|---|---|
| 变量/函数 | camelCase,语义明确 | userProfile, fetchOrderList |
| 常量 | UPPER_SNAKE_CASE | MAX_RETRY_COUNT, API_BASE_URL |
| React 组件 | PascalCase | UserProfileCard, OrderListItem |
| 接口/类型 | PascalCase,不加 I 前缀 | UserProfile, ApiResponse<T> |
| 布尔变量 | is/has/can/should 前缀 | isLoading, hasPermission |
| 事件处理函数 | handle 前缀 | handleSubmit, handleUserClick |
| 文件名(组件) | PascalCase | UserProfileCard.tsx |
| 文件名(工具) | kebab-case | format-date.ts, api-client.ts |
AI 生成代码中的常见命名问题:
typescript
// 不良:含糊的参数和变量名
async function processData(data: any, config: any) {
const result = await fetch(config.url, { body: data });
const temp = await result.json();
return temp;
}
// 改进:明确表达意图
async function submitOrderForm(
orderPayload: CreateOrderRequest,
apiConfig: ApiClientConfig,
): Promise<OrderResponse> {
const response = await fetch(apiConfig.baseUrl + '/orders', {
method: 'POST',
body: JSON.stringify(orderPayload),
});
return response.json() as Promise<OrderResponse>;
}圈复杂度(Cyclomatic Complexity)控制
圈复杂度衡量代码中独立路径的数量。AI 可能生成嵌套层级深、分支多的函数:
typescript
// 圈复杂度 = 9(超标,难以测试)
function calculateDiscount(user: User, order: Order): number {
let discount = 0;
if (user.isPremium) {
if (order.total > 1000) {
if (order.items.length > 5) {
discount = 0.2;
} else {
discount = 0.15;
}
} else {
if (user.loyaltyYears > 3) {
discount = 0.1;
}
}
} else {
if (order.total > 500) {
discount = 0.05;
}
}
return discount;
}
// 重构后:圈复杂度 = 3,可读性提升
function calculateDiscount(user: User, order: Order): number {
if (!user.isPremium) return order.total > 500 ? 0.05 : 0;
if (order.total > 1000) return order.items.length > 5 ? 0.2 : 0.15;
return user.loyaltyYears > 3 ? 0.1 : 0;
}复杂度参考标准:
| 圈复杂度 | 评估 | 建议 |
|---|---|---|
| 1–5 | 简单,易测试 | 保持 |
| 6–10 | 尚可接受 | 考虑拆分 |
| 11–15 | 较复杂 | 必须重构 |
| > 15 | 高风险 | 阻塞合并 |
技术债务管理
使用注释标记技术债务,并在 CI 中统计:
typescript
// TODO(#123): AI 生成了暴力搜索,待优化为二分查找
// FIXME: 此处逻辑与 UserService.findById 重复,待合并
// HACK: 临时绕过第三方 SDK bug,待 v2.3.0 发布后移除
// DEBT: 缺少错误处理,影响用户体验在 CI 中统计并限制 TODO 数量:
yaml
# .github/workflows/quality.yml
- name: 统计技术债务
run: |
count=$(grep -rE "(TODO|FIXME|HACK|DEBT):" src/ | wc -l)
echo "技术债务条目: $count"
if [ "$count" -gt 20 ]; then
echo "技术债务过多,请优先消化后再引入新的 AI 生成代码"
exit 1
fi代码审查中的质量检查要点
在 Review AI 生成代码时,重点关注以下问题:
- 重复代码:AI 有时会生成与现有工具函数功能相同的新函数,应引导复用
- 过度抽象:评估抽象层是否真的有必要,而非为了"看起来像设计模式"
- 错误处理缺失:AI 在示例代码中常省略 try/catch 和边界条件处理
- 类型断言滥用:
as any、as unknown as T是类型安全的漏洞
typescript
// 危险:类型断言绕过了 TypeScript 保护
const user = JSON.parse(response) as User;
// 安全:运行时验证
import { z } from 'zod';
const UserSchema = z.object({ id: z.number(), name: z.string() });
const user = UserSchema.parse(JSON.parse(response));推荐工具链
bash
# 安装完整工具链
npm install -D \
eslint \
@eslint/js \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
eslint-plugin-react \
eslint-plugin-react-hooks \
eslint-plugin-sonarjs \
eslint-plugin-unicorn \
eslint-config-prettier \
prettier \
lint-staged \
huskyjson
// package.json — 提交前自动 lint
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml}": ["prettier --write"]
}
}bash
# 初始化 husky(在 git 提交前自动执行 lint-staged)
npx husky init
echo "npx lint-staged" > .husky/pre-commit通过将上述配置提交到代码仓库,可以确保无论是人工编写还是 AI 生成的代码,在进入代码库之前都经过统一的质量过滤。