关于 audit-code-quality
用于审查并针对性修复 React 和 TypeScript 代码质量问题的技能。它检查反模式、命名、文件组织和模式一致性,并使用代码库自身的检查流程验证改动。
主要功能
- 01查找 React 和 TypeScript 反模式
- 02检查命名与文件组织
- 03审查模式一致性
- 04针对发现的问题进行修复
- 05运行代码库的类型检查、Lint 和测试
适用场景
- 01审查 React 和 TypeScript 代码库
- 02修复已发现的架构或状态问题
- 03合并改动前检查代码约定
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ kensaurus/ skills --skill audit-code-quality安装后在 Claude Code 中输入/audit-code-quality确认已加载。
详细介绍
代码质量审计
自由度:混合——第 1–2 部分的判断 [高自由度];约定检查和验证 [低自由度 — 严格执行]。
审计并修复例外。 发现问题后要修复,而不是报告后就停止。
修复你报告的问题,并修改你指出的文件;报告中未列出的全仓库样式调整或重命名属于另一个会话。进行精准修改——只改有问题的 Hook、键或导入,而不是重写整个文件。过程中遇到的既有 Bug,作为后续事项写入报告。仅在任务要求,或仓库已为相关部分保留测试时,才添加或修改测试;临时 grep 和草稿脚本不要提交。
全仓库 React/TypeScript 反模式,以及命名、组织和模式一致性。针对指定 PR/diff → audit-code-review。
如何推理
- 观察——引用问题点(
file:line),并说明git blame/ CONTRIBUTING 是否标明这是有意为之 - 解读——是否存在 Bug/性能风险,还是仅有风格偏差?
- 分类——反模式 / 命名 / 组织 / 模式分歧 / 有意为之
- 严重程度——运行时 Bug 或用于数据获取的
useEffect= 高;仅命名问题 = 低
示例
观察:
components/PaymentForm.tsx有'use server',并用useEffect获取发票;四个可排序列表都使用key={i}。 解读: 服务端 Action 位于 UI 中;组件重新挂载时会重新触发数据获取;重新排序会导致行组件重新挂载。 分类: 组织 + 用于数据获取的useEffect+ 将索引用作键。 严重程度: 高(Action 位于组件中);中(键)。 发现:PaymentForm.tsx| 高 | 将 Action 移至features/*/server/; 用 TanStack Query 替换数据获取 Effect
任何修改之前 [低自由度 — 严格执行]
cat CONTRIBUTING.md .cursor/rules/*.md 2>/dev/null | head -100 # existing conventions
git log --oneline -20 | grep -i "convention\|pattern\|style" # recent decisions
确认这种“不一致”并非有意为之。修改现有代码之前,先检查 git blame。
第 1 部分 — 反模式 [高自由度]
React
Props 层层传递 → Context 或组合
// Bad: prop drilled through 5+ levels
<Layout user={user}><Sidebar user={user}><UserMenu user={user}><Avatar user={user} />
// Fix: context for global state
const UserContext = createContext<User | null>(null)
const useUser = () => useContext(UserContext)
// Fix: composition for UI concerns
<Layout><Layout.Sidebar><UserMenu /></Layout.Sidebar></Layout>
在 useState 中存储派生状态 → useMemo
// Bad
const [items, setItems] = useState([])
const [filtered, setFiltered] = useState([])
useEffect(() => { setFiltered(items.filter(i => i.active)) }, [items])
// Fix
const filtered = useMemo(() => items.filter(i => i.active), [items])
使用 useEffect 获取数据 → 服务端组件或 TanStack Query
// Fix (Next.js 16 Server Component)
async function DataDisplay() {
const data = await db.getData()
return <div>{data.name}</div>
}
// Fix (client with TanStack Query)
const { data, isLoading } = useQuery({ queryKey: ['data'], queryFn: fetchData })
依赖数组中包含对象/数组 → 使用 memo 或解构
// Bad: new object every render → infinite loop
useEffect(() => { doSomething(options) }, [options])
// Fix
const options = useMemo(() => ({ page, limit }), [page, limit])
useEffect(() => { doSomething(options) }, [options])
在动态列表中将索引用作键 → 稳定 ID
// Bad
{items.map((item, i) => <Item key={i} />)}
// Fix
{items.map(item => <Item key={item.id} />)}
巨型组件 → 组合
// Split by responsibility
export function UserDashboard() {
const user = useUser()
return (
<DashboardLayout>
<UserHeader user={user} />
<UserStats userId={user.id} />
<RecentActivity userId={user.id} />
</DashboardLayout>
)
}
TypeScript
// Bad: any
function processData(data: any) { return data.items.map((i: any) => i.name) }
// Fix: proper types + Zod validation
const DataSchema = z.object({ items: z.array(z.object({ id: z.string(), name: z.string() })) })
function processData(data: z.infer<typeof DataSchema>) { return data.items.map(i => i.name) }
// Bad: enums (runtime object, not tree-shakeable)
enum Status { Pending = 'pending', Active = 'active' }
// Fix: union types
type Status = 'pending' | 'active'
// Fix: exhaustive switch
function handle(s: Status): string {
switch (s) {
case 'pending': return 'Waiting'
case 'active': return 'Running'
default:
const _: never = s
throw new Error(`Unknown: ${_}`)
}
}
状态管理
// Rule of thumb:
// URL state (nuqs) → shareable, bookmarkable
// Global state (Zustand) → cross-component, persisted
// Local state (useState) → component-specific, ephemeral
// Stale closure fix
useEffect(() => {
const id = setInterval(() => setCount(c => c + 1), 1000) // functional update
return () => clearInterval(id)
}, [])
架构
// Circular deps → extract shared code / dependency inversion
// Business logic in components → move to lib/feature/calculations.ts
// God files → feature-based organisation:
lib/
date/format.ts
currency/format.ts
validation/schemas.ts
第 2 部分 — 一致性审计 [高自由度;grep 检查为低自由度]
命名约定
| 元素 | 预期格式 | 检查 |
|---|---|---|
| 组件 | PascalCase | userCard 与 UserCard |
| Hook | use 前缀 | fetchData 与 useFetchData |
| 工具函数 | camelCase | format_date 与 formatDate |
| 常量 | SCREAMING_SNAKE | apiUrl 与 API_URL |
| 文件 | kebab-case | UserCard.tsx 与 user-card.tsx |
| 布尔型属性 | is/has/should | loading 与 isLoading |
rg "export (function|const|class) [a-z]" --type tsx # lowercase component exports
rg "use[A-Z]" --type ts # hook patterns
rg "export default" --type tsx -l | head -20 # mixed default/named exports
文件组织(按功能切片)
src/
features/{name}/
components/ # UI only
hooks/ # custom hooks
server/ # server actions
types.ts
schemas.ts
components/ui/ # shared primitives
lib/ # global utilities
警示项:
- 在
/lib或/utils中放置组件 - 在组件文件中定义服务端 Action
- 类型定义分散在各个组件文件中
- 在组件中内联 Zod Schema
rg "z\.object" --glob "*/components/*" # inline schemas
rg "'use server'" --glob "*/components/*" # actions in wrong place
rg "from '\.\." --type tsx | head -20 # relative imports instead of @/
模式一致性
| 关注点 | 检查 |
|---|---|
| 服务端状态 | 是否全部使用 TanStack Query,还是混用了 useEffect? |
| 表单 | 是否全部使用 React Hook Form,还是也使用受控输入? |
| 错误处理 | ActionResult 的结构是否一致? |
| 样式 | 是否处处使用 cn()?是否通过 CSS 变量实现深色模式? |
| 测试 | 使用 *.test.ts 还是 __tests__/?Mock 方式是否一致? |
一致性报告模板
# Code Quality Audit
## Summary
- Verdict: [one line — what blocks, what is drift]
- Critical findings: X
## Anti-patterns found
| Pattern | Files | Severity |
|---------|-------|----------|
| useEffect for data | 3 files | High |
| Index as key | 2 files | Medium |
## Naming convention findings
| Element | Expected | Actual | Files |
|---------|----------|--------|-------|
| Components | PascalCase | Mixed | 4 |
## Organisation findings
- Server actions found in: components/PaymentForm.tsx
- Types scattered in: 6 component files
## Priority fixes
1. Move server actions to features/*/server/
2. Replace useEffect data fetching with TanStack Query
3. Standardise component naming to PascalCase
## Conventions to document
1. Decision on default vs named exports
2. Where Zod schemas live
反模式检测清单
React 检查
- 不使用
useEffect处理派生状态 - 动态列表中不使用索引作为键
- 依赖数组中不包含对象/数组
- 组件少于 300 行
- Props 传递不超过 2 层
TypeScript 检查
- 不使用
any(使用unknown+ 验证) - 不使用不安全的类型断言
-
switch语句覆盖所有情况 - 所有外部数据都有 Zod Schema
架构检查
- 无循环依赖
- 业务逻辑与 UI 分离
- 文件不超过 400 行
- 模块边界清晰
修复前自我审查 [LOW freedom — do not skip]
- 有据可查 — 提供
file:line或 rg 命中结果,而不是「代码库感觉很乱」 - 可复现 — 按照该约定执行 grep 仍能找到问题
- 严重性合理 — High = 缺陷/性能问题,而非命名偏好
- 责任归属正确 — 此 PR/diff →
audit-code-review - 避免虚假安全感 — 已检查
git blame;保留有意为之且正常工作的代码
验证 [LOW freedom — run exactly]
- 使用代码库自带的脚本进行类型检查(
package.json→typecheck;否则运行tsc --noEmit) - 使用代码库自带的脚本进行 lint 检查,不要使用通用的
eslint src/ - 运行代码库的测试脚本,并确认没有新增失败
- 在
CONTRIBUTING.md或.cursor/rules/中记录任何强制执行的规范