# 代码质量规范(Code Quality Standards) > **模块**: 01_Architecture - 代码质量与 ESLint 规范 > **更新日期**: 2026-03-20 > **适用范围**: 全项目(dashboard、server、extension、node-agent) --- ## 1. 概述(Overview) ### 1.1 目标 - **代码一致性**:统一代码风格和结构 - **类型安全**:通过 ESLint + TypeScript 确保类型正确 - **可维护性**:提高代码可读性和可维护性 - **自动化检查**:通过工具链自动检查代码质量 ### 1.2 工具链 | 工具 | 用途 | 优先级 | |------|------|--------| | **ESLint** | 代码质量检查 | P0 | | **Prettier** | 代码格式化 | P0 | | **TypeScript** | 类型检查 | P0 | | **Husky** | Git 钩子 | P1 | | **lint-staged** | 提交前检查 | P1 | --- ## 2. ESLint 配置(ESLint Configuration) ### 2.1 安装依赖 ```bash # 核心依赖 npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin # 额外插件 npm install -D eslint-plugin-prettier eslint-config-prettier npm install -D eslint-plugin-import eslint-plugin-boundaries ``` ### 2.2 基础配置(.eslintrc.js) ```javascript module.exports = { env: { node: true, es2021: true, browser: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:import/recommended', 'plugin:import/typescript', 'plugin:prettier/recommended' ], parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 'latest', sourceType: 'module', project: './tsconfig.json', tsconfigRootDir: __dirname }, plugins: [ '@typescript-eslint', 'import', 'boundaries' ], settings: { 'import/resolver': { typescript: { alwaysTryTypes: true, project: './tsconfig.json' } }, 'boundaries/elements': [ { type: 'controller', pattern: 'src/api/controllers/*' }, { type: 'service', pattern: 'src/services/*' }, { type: 'repository', pattern: 'src/repositories/*' }, { type: 'model', pattern: 'src/models/*' }, { type: 'dto', pattern: 'src/dto/*' } ] }, rules: { // TypeScript 核心规则 '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/explicit-function-return-type': 'error', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/strict-boolean-expressions': 'warn', '@typescript-eslint/no-unnecessary-type-assertion': 'error', '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports', disallowTypeAnnotations: false }], '@typescript-eslint/no-non-null-assertion': 'warn', // Import 规则 'import/order': ['error', { groups: [ 'builtin', 'external', 'internal', 'parent', 'sibling', 'index' ], 'newlines-between': 'always', alphabetize: { order: 'asc', caseInsensitive: true } }], 'import/no-duplicates': 'error', 'import/no-cycle': 'error', 'import/no-unresolved': 'off', // Boundaries 规则(架构分层) 'boundaries/element-types': ['error', { default: 'disallow', rules: [ { from: 'controller', allow: ['service', 'dto'] }, { from: 'service', allow: ['repository', 'model', 'dto'] }, { from: 'repository', allow: ['model'] }, { from: 'model', allow: [] } ] }], // 通用规则 'no-console': ['warn', { allow: ['warn', 'error'] }], 'no-debugger': 'error', 'no-alert': 'error', 'no-var': 'error', 'prefer-const': 'error', 'prefer-arrow-callback': 'error', 'no-const-assign': 'error', 'no-dupe-keys': 'error', 'no-duplicate-case': 'error', 'no-empty': 'error', 'no-eval': 'error', 'no-implied-eval': 'error', 'no-irregular-whitespace': 'error', 'no-iterator': 'error', 'no-multi-spaces': 'error', 'no-new-wrappers': 'error', 'no-return-await': 'error', 'no-sequences': 'error', 'no-shadow-restricted-names': 'error', 'no-sparse-arrays': 'error', 'no-throw-literal': 'error', 'no-unreachable': 'error', 'no-unsafe-finally': 'error', 'no-useless-concat': 'error', 'no-useless-return': 'error', 'no-with': 'error', 'radix': 'error', 'yoda': 'error', // Prettier 集成 'prettier/prettier': 'error' }, ignorePatterns: [ 'dist', 'node_modules', '*.config.js', '*.config.ts', '.umi', '.umi-production' ] } ``` ### 2.3 模块特定配置 #### Dashboard(前端) ```javascript module.exports = { extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'plugin:react-hooks/recommended', 'plugin:jsx-a11y/recommended', 'plugin:prettier/recommended' ], plugins: ['react', 'react-hooks', 'jsx-a11y'], settings: { react: { version: 'detect' } }, rules: { 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn' } } ``` #### Server(后端) ```javascript module.exports = { env: { node: true, es2021: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended' ], rules: { 'no-console': ['warn', { allow: ['warn', 'error'] }] } } ``` --- ## 3. Prettier 配置(Prettier Configuration) ### 3.1 安装依赖 ```bash npm install -D prettier eslint-config-prettier eslint-plugin-prettier ``` ### 3.2 配置文件(.prettierrc.js) ```javascript module.exports = { printWidth: 100, tabWidth: 2, useTabs: false, semi: true, singleQuote: true, quoteProps: 'as-needed', jsxSingleQuote: false, trailingComma: 'es5', bracketSpacing: true, bracketSameLine: false, arrowParens: 'always', proseWrap: 'preserve', htmlWhitespaceSensitivity: 'css', endOfLine: 'lf', embeddedLanguageFormatting: 'auto' } ``` ### 3.3 忽略文件(.prettierignore) ``` node_modules dist build coverage *.min.js *.min.css package-lock.json yarn.lock pnpm-lock.yaml .umi .umi-production ``` --- ## 4. 代码风格规范(Code Style Standards) ### 4.1 命名规范 | 类型 | 命名规则 | 示例 | |------|----------|------| | **变量/函数** | camelCase | `getUserData`, `userName` | | **类/接口/类型** | PascalCase | `UserService`, `Product` | | **常量** | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT`, `API_BASE_URL` | | **私有成员** | camelCase + `_` 前缀 | `_privateMethod`, `_internalState` | | **枚举** | PascalCase | `Status`, `OrderStatus` | | **文件名** | PascalCase (组件) / kebab-case (工具) | `UserList.tsx`, `api-utils.ts` | ### 4.2 注释规范 #### JSDoc 注释 ```typescript /** * 获取用户信息 * * @param userId - 用户ID * @param includeProfile - 是否包含个人资料 * @returns 用户信息对象 * @throws {Error} 当用户不存在时抛出错误 * * @example * ```typescript * const user = await getUser('123', true) * console.log(user.name) * ``` */ async function getUser( userId: string, includeProfile: boolean = false ): Promise { const user = await userRepository.findById(userId) if (!user) { throw new Error(`User not found: ${userId}`) } if (includeProfile) { return { ...user, profile: await profileRepository.findByUserId(userId) } } return user } ``` #### 单行注释 ```typescript // 计算订单总金额 const totalAmount = calculateTotalAmount(items) // TODO: 需要优化性能 const result = heavyComputation(data) ``` #### 多行注释 ```typescript /* * 订单处理流程: * 1. 验证订单数据 * 2. 检查库存 * 3. 创建支付记录 * 4. 更新订单状态 */ ``` ### 4.3 代码组织 #### 文件结构 ```typescript // 1. 导入(按顺序:Node.js 内置、第三方库、内部模块) import { promises as fs } from 'fs' import axios from 'axios' import { UserService } from '@/services/UserService' import type { User } from '@/types/domain/User' // 2. 类型定义 interface UserDTO { id: string name: string email: string } // 3. 常量定义 const MAX_RETRY_COUNT = 3 const API_TIMEOUT = 5000 // 4. 类/函数定义 export class UserController { // ... } // 5. 导出 export { UserDTO } ``` #### 导入顺序 ```typescript // 1. Node.js 内置模块 import { promises as fs } from 'fs' import path from 'path' // 2. 第三方库 import axios from 'axios' import { z } from 'zod' // 3. 内部模块(按路径层级) import { UserService } from '@/services/UserService' import { UserRepository } from '@/repositories/UserRepository' import type { User } from '@/types/domain/User' import { validateUser } from '@/utils/validators' // 4. 相对路径导入 import { formatDate } from './utils/date' ``` --- ## 5. TypeScript 特定规范(TypeScript Specific Standards) ### 5.1 类型定义 ```typescript // ✅ 正确:使用 interface 定义对象类型 interface User { id: string name: string email: string } // ✅ 正确:使用 type 定义联合类型、交叉类型 type Status = 'active' | 'inactive' | 'pending' type UserWithProfile = User & { profile: Profile } // ❌ 错误:使用 type 定义简单对象类型 type User = { id: string name: string email: string } ``` ### 5.2 泛型使用 ```typescript // ✅ 正确:使用泛型提高代码复用性 function fetchData(url: string): Promise { return axios.get(url).then(res => res.data) } // ✅ 正确:使用泛型约束 function processItem(item: T): void { console.log(item.id) } // ❌ 错误:过度使用泛型 function process(a: T, b: U, c: V, d: W): void { // ... } ``` ### 5.3 类型守卫 ```typescript // ✅ 正确:使用类型守卫 function isProduct(data: unknown): data is Product { return ( typeof data === 'object' && data !== null && 'id' in data && 'name' in data && 'price' in data ) } function handleData(data: unknown) { if (isProduct(data)) { // TypeScript 知道 data 是 Product 类型 console.log(data.name) } } ``` ### 5.4 可选链和空值合并 ```typescript // ✅ 正确:使用可选链 const userName = user?.profile?.name // ✅ 正确:使用空值合并 const displayName = userName ?? 'Anonymous' // ✅ 正确:结合使用 const value = obj?.prop ?? defaultValue // ❌ 错误:过度使用可选链 const value = obj?.prop?.nested?.value?.toString() ``` --- ## 6. React 特定规范(React Specific Standards) ### 6.1 组件定义 ```typescript // ✅ 正确:使用函数组件 + TypeScript interface Props { title: string count: number onAction: () => void } export function ProductCard({ title, count, onAction }: Props) { return (

{title}

Count: {count}

) } // ✅ 正确:使用 React.FC(不推荐,但可用) export const ProductCard: React.FC = ({ title, count, onAction }) => { return (

{title}

Count: {count}

) } ``` ### 6.2 Hooks 使用 ```typescript // ✅ 正确:使用自定义 Hook function useUserData(userId: string) { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { async function fetchUser() { try { setLoading(true) const data = await userService.getUser(userId) setUser(data) } catch (err) { setError(err as Error) } finally { setLoading(false) } } fetchUser() }, [userId]) return { user, loading, error } } // ✅ 正确:在组件中使用 function UserProfile({ userId }: { userId: string }) { const { user, loading, error } = useUserData(userId) if (loading) return
Loading...
if (error) return
Error: {error.message}
if (!user) return
User not found
return
{user.name}
} ``` ### 6.3 Props 类型定义 ```typescript // ✅ 正确:明确的 Props 类型 interface ProductListProps { products: Product[] loading?: boolean onProductClick: (product: Product) => void className?: string } export function ProductList({ products, loading = false, onProductClick, className }: ProductListProps) { if (loading) return
Loading...
return (
{products.map(product => ( onProductClick(product)} /> ))}
) } ``` --- ## 7. 后端特定规范(Backend Specific Standards) ### 7.1 Controller 层 ```typescript // ✅ 正确:Controller 只负责请求/响应 export class UserController { constructor(private readonly userService: UserService) {} async getUser(req: Request, res: Response): Promise { try { const { userId } = req.params const user = await this.userService.getUser(userId) res.json({ success: true, data: user }) } catch (error) { res.status(500).json({ success: false, error: error instanceof Error ? error.message : 'Unknown error' }) } } } ``` ### 7.2 Service 层 ```typescript // ✅ 正确:Service 负责业务逻辑 export class UserService { constructor( private readonly userRepository: UserRepository, private readonly profileRepository: ProfileRepository ) {} async getUser(userId: string): Promise { const user = await this.userRepository.findById(userId) if (!user) { throw new Error(`User not found: ${userId}`) } const profile = await this.profileRepository.findByUserId(userId) return { ...user, profile } } } ``` ### 7.3 Repository 层 ```typescript // ✅ 正确:Repository 只负责数据访问 export class UserRepository { constructor(private readonly db: Knex) {} async findById(id: string): Promise { const row = await this.db('users').where({ id }).first() return row ? this.mapToEntity(row) : null } private mapToEntity(row: any): User { return { id: row.id, name: row.name, email: row.email, createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at) } } } ``` --- ## 8. 测试规范(Testing Standards) ### 8.1 测试文件命名 ``` src/ services/ UserService.ts UserService.test.ts # 单元测试 UserService.integration.test.ts # 集成测试 ``` ### 8.2 测试结构 ```typescript describe('UserService', () => { let userService: UserService let mockUserRepository: jest.Mocked beforeEach(() => { mockUserRepository = { findById: jest.fn(), create: jest.fn(), update: jest.fn(), delete: jest.fn() } as any userService = new UserService(mockUserRepository) }) describe('getUser', () => { it('should return user when user exists', async () => { const mockUser = { id: '123', name: 'John Doe', email: 'john@example.com' } mockUserRepository.findById.mockResolvedValue(mockUser) const result = await userService.getUser('123') expect(result).toEqual(mockUser) expect(mockUserRepository.findById).toHaveBeenCalledWith('123') }) it('should throw error when user does not exist', async () => { mockUserRepository.findById.mockResolvedValue(null) await expect(userService.getUser('123')).rejects.toThrow('User not found: 123') }) }) }) ``` --- ## 9. 性能优化规范(Performance Standards) ### 9.1 避免不必要的渲染 ```typescript // ✅ 正确:使用 React.memo export const ProductCard = React.memo(function ProductCard({ product }: { product: Product }) { return
{product.name}
}) // ✅ 正确:使用 useMemo function ProductList({ products }: { products: Product[] }) { const sortedProducts = useMemo( () => [...products].sort((a, b) => a.name.localeCompare(b.name)), [products] ) return (
{sortedProducts.map(product => ( ))}
) } // ✅ 正确:使用 useCallback function ProductList({ products, onProductClick }: { products: Product[], onProductClick: (product: Product) => void }) { const handleClick = useCallback( (product: Product) => { onProductClick(product) }, [onProductClick] ) return (
{products.map(product => ( ))}
) } ``` ### 9.2 避免内存泄漏 ```typescript // ✅ 正确:清理副作用 function useInterval(callback: () => void, delay: number) { useEffect(() => { const intervalId = setInterval(callback, delay) return () => { clearInterval(intervalId) } }, [callback, delay]) } // ✅ 正确:取消请求 function useUserData(userId: string) { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { const abortController = new AbortController() async function fetchUser() { try { setLoading(true) const data = await userService.getUser(userId, { signal: abortController.signal }) setUser(data) } catch (error) { if (error.name !== 'AbortError') { console.error(error) } } finally { setLoading(false) } } fetchUser() return () => { abortController.abort() } }, [userId]) return { user, loading } } ``` --- ## 10. 安全规范(Security Standards) ### 10.1 输入验证 ```typescript // ✅ 正确:使用 zod 验证输入 const CreateUserSchema = z.object({ name: z.string().min(1).max(100), email: z.string().email(), password: z.string().min(8).regex(/[A-Z]/).regex(/[0-9]/) }) async function createUser(data: unknown): Promise { const validatedData = CreateUserSchema.parse(data) return userRepository.create(validatedData) } ``` ### 10.2 SQL 注入防护 ```typescript // ✅ 正确:使用参数化查询 async function getUserById(id: string): Promise { const row = await this.db('users').where({ id }).first() return row ? this.mapToEntity(row) : null } // ❌ 错误:字符串拼接 SQL async function getUserByIdBad(id: string): Promise { const row = await this.db.raw(`SELECT * FROM users WHERE id = '${id}'`) return row ? this.mapToEntity(row) : null } ``` ### 10.3 XSS 防护 ```typescript // ✅ 正确:React 自动转义 function UserDisplay({ name }: { name: string }) { return
{name}
} // ✅ 正确:使用 DOMPurify 清理 HTML import DOMPurify from 'dompurify' function RichTextContent({ html }: { html: string }) { const cleanHtml = DOMPurify.sanitize(html) return
} ``` --- ## 11. Git 提交规范(Git Commit Standards) ### 11.1 提交信息格式 ``` ():