编码规范

跨项目通用编码规范基线,涵盖命名约定、不可变性、可读性(KISS/DRY/YAGNI)、错误处理及代码异味检测。覆盖 TypeScript/JavaScript、React、API 设计、文件组织、性能优化和测试标准,作为项目代码质量的共享底线,而非特定框架的详细指南。

核心定位

跨项目通用编码规范基线

作为所有项目的共享底线(shared floor),而非特定框架的详细手册。专注于命名、不可变性、可读性、错误处理等通用原则,与 frontend-patternsbackend-patternsapi-design 等专项技能互补。当需要最短可复用规则层而非完整技能走查时,优先使用 rules/common/coding-style.md

适用场景

  • 启动新项目或模块时建立规范
  • 审查代码质量与可维护性
  • 重构现有代码以遵循约定
  • 强制执行命名、格式或结构一致性
  • 配置 lint、format 或类型检查规则
  • 新成员入职培训

范围边界

涵盖:描述性命名、不可变性默认、可读性(KISS/DRY/YAGNI)、错误处理期望、代码审查

不涵盖(由更专项技能负责):React 组合/hooks/渲染模式、后端架构/API 设计/数据库分层、特定框架的详细指导

四大代码质量原则

原则 核心要求
Readability First(可读性优先) 代码读比写多;命名清晰;自解释代码优于注释;格式一致
KISS 最简单的可行方案;避免过度工程;不 premature optimization;易懂 > 聪明
DRY 提取公共逻辑为函数;创建可复用组件;跨模块共享工具;避免复制粘贴
YAGNI 不提前构建未需要的功能;避免推测性泛化;需要时才增加复杂度;先简单后重构

TypeScript/JavaScript 标准

变量与函数命名

  • 变量:描述性名词,如 marketSearchQueryisUserAuthenticatedtotalRevenue
  • 函数:动词-名词模式,如 fetchMarketData()calculateSimilarity()isValidEmail()
  • 避免:qflagx 等无意义缩写;仅名词的函数名如 market()email()

不可变性模式(关键)

// 推荐:始终使用展开运算符
const updatedUser = { ...user, name: 'New Name' }
const updatedArray = [...items, newItem]

// 禁止:直接修改
user.name = 'New Name'  // ❌
items.push(newItem)      // ❌

错误处理

  • 使用 try/catch 包裹异步操作
  • 提供有意义的错误信息
  • 在错误边界处理,不吞掉异常

Async/Await 最佳实践

// 推荐:可并行时 Promise.all
const [users, markets, stats] = await Promise.all([
  fetchUsers(), fetchMarkets(), fetchStats()
])

// 禁止:不必要的串行
const users = await fetchUsers()
const markets = await fetchMarkets()  // ❌

类型安全

  • 使用 interface 定义数据结构
  • 避免 any,使用具体类型或 unknown + 类型守卫
  • 函数返回值明确标注类型

React 最佳实践

组件结构

  • 使用函数组件 + TypeScript Props 接口
  • Props 解构并设置默认值
  • 避免无类型的 props 参数

自定义 Hooks

  • use 前缀命名
  • 封装可复用逻辑(如防抖、防抖、数据获取)
  • 遵循 Hooks 规则(只在顶层调用)

状态管理

  • 基于前状态更新时使用函数式更新:setCount(prev => prev + 1)
  • 避免直接引用可能过时的状态变量

条件渲染

  • 使用 && 短路运算符进行简单条件渲染
  • 避免嵌套三元运算符("三元地狱")

API 设计标准

REST 约定

  • URL 使用复数名词和 kebab-case
  • HTTP 方法语义化:GET 获取、POST 创建、PUT/PATCH 更新、DELETE 删除
  • 查询参数用于过滤、分页、排序

响应格式

// 推荐:统一结构
interface ApiResponse<T> {
  success: boolean
  data?: T
  error?: string
  meta?: { total: number; page: number; limit: number }
}

输入校验

  • 使用 Schema 校验库(如 Zod)
  • 校验失败返回 400 并附详细错误信息
  • 区分校验错误与业务错误

文件组织

推荐目录结构

src/
├── app/           # 应用入口 / 路由
│   ├── api/       # API 路由
│   └── (auth)/    # 路由分组
├── components/    # React 组件
│   ├── ui/        # 通用 UI 组件
│   ├── forms/     # 表单组件
│   └── layouts/   # 布局组件
├── hooks/         # 自定义 Hooks
├── lib/           # 工具与配置
│   ├── api/       # API 客户端
│   ├── utils/     # 辅助函数
│   └── constants/ # 常量
├── types/         # TypeScript 类型
└── styles/        # 全局样式

文件命名

  • 组件:PascalCase(如 Button.tsx
  • Hooks:camelCaseuse 前缀(如 useAuth.ts
  • 工具函数:camelCase(如 formatDate.ts
  • 类型定义:camelCase.types 后缀(如 market.types.ts

注释与文档

何时注释

  • 解释 WHY 而非 WHAT
  • 说明非常规选择的原因
  • 复杂算法或业务逻辑的上下文
// 推荐:解释原因
// 使用指数退避避免在故障期间压垮 API
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)

// 禁止:陈述显而易见的事
// 计数器加 1
count++

JSDoc 用于公共 API

  • @param — 参数说明
  • @returns — 返回值说明
  • @throws — 可能抛出的异常
  • @example — 使用示例

性能最佳实践

Memoization

  • useMemo — 缓存昂贵计算
  • useCallback — 缓存事件处理函数
  • 注意:Array.prototype.sort 会原地修改,需先复制

懒加载

  • 使用 React.lazy + Suspense 延迟加载重组件
  • 路由级别代码分割

数据库查询

  • 仅选择需要的列,避免 SELECT *
  • 使用分页限制返回数据量

测试标准

AAA 模式(Arrange-Act-Assert)

test('calculates similarity correctly', () => {
  // Arrange
  const vector1 = [1, 0, 0]
  const vector2 = [0, 1, 0]

  // Act
  const similarity = calculateCosineSimilarity(vector1, vector2)

  // Assert
  expect(similarity).toBe(0)
})

测试命名

  • 描述具体行为场景
  • 包含输入、预期输出和边界条件
  • 避免 test('works')test('test search') 等模糊名称

代码检测

1. 过长函数

  • 限制:单个函数不超过 50 行
  • 拆分:提取为更小、更专注的函数
  • 每个函数只做一件事

2. 深层嵌套

  • 限制:嵌套不超过 3 层
  • 优化:使用提前返回替代深层 if 嵌套
// 禁止:5+ 层嵌套
if (user) { if (user.isAdmin) { if (market) { ... } } }

// 推荐:提前返回
if (!user) return
if (!user.isAdmin) return
if (!market) return

3. 魔法数字

  • 禁止:未解释的数字字面量
  • 推荐:使用命名常量
v1.0.0 2026-07-16
下载