agentic-awesome-skills 编码规范实战详解:覆盖 TypeScript、React、Node.js 与 API 设计的通用代码质量标准【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills本文以 AAS(agentic-awesome-skills)仓库中cc-skill-coding-standards技能的详细指南(references/detailed-guide.md)为核心骨架展开,逐节完整继承其命名规范、不可变更新、错误处理、类型安全、组件结构、API 契约、文件组织、注释、性能优化、测试与坏味道检测等全部要点,并结合 SKILL.md 的元信息与 skills_index.json 的索引记录加以佐证。读者读完后,可以把它当作一套可直接落地的「可执行编码标准清单」,在编写或评审任何 TypeScript / JavaScript / React / Node.js 项目代码时对照使用。cc-skill-coding-standards是 AAS 技能库中面向所有项目通用的编码标准类技能:它不绑定某个业务模块,而是定义了一套跨项目适用的「质量底线」。从仓库索引看,该技能被标记为category: meta、risk: critical、source: community,加入时间为2026-02-27,并在 skills_index.json 中声明对 Codex 与 Claude 两类 Agent 目标均supported(plugin.targets.codex/plugin.targets.claude均为supported)。技能根文件 SKILL.md 明确要求:在执行本技能前必须先通读详细指南,并把其中的安全前提与校验要求视为强制性约束。一、代码质量四项核心原则所有具体规范都建立在四条经典工程原则之上,它们是后续每个章节的判据来源。1. Readability First(可读性优先)代码被阅读的次数远多于被书写的次数,可读性是第一优先级;变量与函数命名必须清晰,让意图自明;优先「自文档化代码」(self-documenting code),注释只补充代码无法表达的信息;保持统一的格式化风格,减少读者切换成本。2. KISS(Keep It Simple, Stupid)选择能工作的最简单方案,而不是最「聪明」的方案;避免过度设计(over-engineering);不做过早优化(premature optimization);「易于理解」永远优于「炫技代码」。3. DRY(Don't Repeat Yourself)把公共逻辑抽取为函数;创建可复用的组件与工具模块;跨模块共享工具函数;杜绝复制粘贴式编程——每处重复都是未来 bug 的潜在来源。4. YAGNI(You Aren't Gonna Need It)不在需求到来之前预构功能;避免投机性泛化(speculative generality);只在确实需要时增加复杂度;先简单起步,需要时再重构演进。这四条原则在 AAS 技能库中被定位为risk: critical,意味着在代码生成、代码评审类工作流中,它们属于「违反即扣分」的硬性约束,而非可选项。二、TypeScript / JavaScript 编码标准1. 变量命名:描述性优于缩写使用能表达语义的完整名称,杜绝无意义的单字母或模糊布尔量:// ✅ GOOD: Descriptive names const marketSearchQuery = 'election' const isUserAuthenticated = true const totalRevenue = 1000 // ❌ BAD: Unclear names const q = 'election' const flag = true const x = 1000布尔值建议采用is/has/can等前缀(如isUserAuthenticated),数量型变量采用total/count等前缀(如totalRevenue),搜索查询等上下文型变量带上领域词(如marketSearchQuery)。2. 函数命名:动词 + 名词 模式函数名应描述「动作 + 对象」,让调用点读起来像一句自然语言:// ✅ GOOD: Verb-noun pattern async function fetchMarketData(marketId: string) { } function calculateSimilarity(a: number[], b: number[]) { } function isValidEmail(email: string): boolean { } // ❌ BAD: Unclear or noun-only async function market(id: string) { } function similarity(a, b) { } function email(e) { }同时为函数标注完整的参数类型与返回值类型(如a: number[]、: boolean),让类型成为签名的一部分。3. 不可变更新模式(CRITICAL,强制)React / Node.js 项目中对象与数组的更新必须使用展开运算符(spread)创建新引用,严禁直接修改原对象或原数组——这是避免 React 渲染失效、并发状态错乱的最关键约定:// ✅ ALWAYS use spread operator const updatedUser = { ...user, name: 'New Name' } const updatedArray = [...items, newItem] // ❌ NEVER mutate directly user.name = 'New Name' // BAD items.push(newItem) // BAD注意:新增数组元素使用[...items, newItem]生成新数组,而不是items.push(...);更新对象属性使用{ ...user, name: 'New Name' },而不是直接赋值user.name = ...。该节在原文档中被显式标注为 CRITICAL 级别,属于必须无条件遵守的硬性规则。4. 错误处理:全面捕获,绝不静默失败异步函数必须捕获网络 / 状态类错误,检查 HTTP 状态码,并向上层抛出带上下文的新错误:// ✅ GOOD: Comprehensive error handling async function fetchData(url: string) { try { const response = await fetch(url) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } return await response.json() } catch (error) { console.error('Fetch failed:', error) throw new Error('Failed to fetch data') } } // ❌ BAD: No error handling async function fetchData(url) { const response = await fetch(url) return response.json() }要点:response.ok === false时显式抛错并携带status/statusText;catch 块中先记录原始错误(console.error),再抛出对调用方有意义的封装错误,避免吞掉异常或丢失根因。5. Async / Await:能并行就不要串行互不依赖的异步任务用Promise.all并行执行,减少总等待时间:// ✅ GOOD: Parallel execution when possible const [users, markets, stats] = await Promise.all([ fetchUsers(), fetchMarkets(), fetchStats() ]) // ❌ BAD: Sequential when unnecessary const users = await fetchUsers() const markets = await fetchMarkets() const stats = await fetchStats()6. 类型安全:消灭any用接口(interface)与联合类型(union type)描述数据形状,函数签名返回强类型 Promise:// ✅ GOOD: Proper types interface Market { id: string name: string status: 'active' | 'resolved' | 'closed' created_at: Date } function getMarket(id: string): Promise<Market> { // Implementation } // ❌ BAD: Using 'any' function getMarket(id: any): Promise<any> { // Implementation }status使用字面量联合类型'active' | 'resolved' | 'closed'而非string,让非法状态在编译期即被拦截;任何any的出现都应视为技术债。三、React 最佳实践1. 组件结构:函数组件 + 完整 Props 类型组件必须使用带类型的函数组件,通过interface显式声明 Props,并给出默认值:// ✅ GOOD: Functional component with types interface ButtonProps { children: React.ReactNode onClick: () => void disabled?: boolean variant?: 'primary' | 'secondary' } export function Button({ children, onClick, disabled = false, variant = 'primary' }: ButtonProps) { return ( <button onClick={onClick} disabled={disabled} className={`btn btn-${variant}`} > {children} </button> ) } // ❌ BAD: No types, unclear structure export function Button(props) { return <button onClick={props.onClick}>{props.children}</button> }variant同样采用联合类型限定取值范围;可选 Props(disabled、variant)在解构时赋予默认值,保证组件行为可预测。2. 自定义 Hooks:封装可复用逻辑把可复用的副作用逻辑封装为use前缀的自定义 Hook,并保持泛型通用:// ✅ GOOD: Reusable custom hook export function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState<T>(value) useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value) }, delay) return () => clearTimeout(handler) }, [value, delay]) return debouncedValue } // Usage const debouncedQuery = useDebounce(searchQuery, 500)要点:useEffect的 cleanup 中调用clearTimeout防止内存泄漏;依赖数组[value, delay]保证 timer 在输入变化时重置;返回去抖后的值供组件直接消费。3. 状态管理:优先函数式更新基于前一个状态计算新状态时,使用函数式更新(setCount(prev => prev + 1)),避免异步场景中的过期闭包(stale closure):// ✅ GOOD: Proper state updates const [count, setCount] = useState(0) // Functional update for state based on previous state setCount(prev => prev + 1) // ❌ BAD: Direct state reference setCount(count + 1) // Can be stale in async scenarios4. 条件渲染:短路表达式,拒绝三元地狱加载、错误、数据三种状态分别用&&短路渲染,保持 JSX 平铺可读:// ✅ GOOD: Clear conditional rendering {isLoading && <Spinner />} {error && <ErrorMessage error={error} />} {data && <DataDisplay data={data} />} // ❌ BAD: Ternary hell {isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}四、API 设计标准1. REST 路由约定资源名使用复数名词,方法语义与 HTTP 动词一一对应:GET /api/markets # List all markets GET /api/markets/:id # Get specific market POST /api/markets # Create new market PUT /api/markets/:id # Update market (full) PATCH /api/markets/:id # Update market (partial) DELETE /api/markets/:id # Delete market # Query parameters for filtering GET /api/markets?status=active&limit=10&offset=0约定要点:PUT表示全量替换,PATCH表示局部更新;列表接口统一通过 query string 提供过滤(status)与分页(limit/offset)。2. 统一响应格式所有接口返回一致的响应信封(envelope),成功与失败路径结构对称:// ✅ GOOD: Consistent response structure interface ApiResponse<T> { success: boolean data?: T error?: string meta?: { total: number page: number limit: number } } // Success response return NextResponse.json({ success: true, data: markets, meta: { total: 100, page: 1, limit: 10 } }) // Error response return NextResponse.json({ success: false, error: 'Invalid request' }, { status: 400 })meta中携带分页元数据(total/page/limit),前端可直接渲染分页器;错误响应同时配合 HTTP 状态码(如 400)。3. 输入校验:Schema 优先使用 zod 在进入业务逻辑前完成请求体校验,失败时返回结构化错误明细:import { z } from 'zod' // ✅ GOOD: Schema validation const CreateMarketSchema = z.object({ name: z.string().min(1).max(200), description: z.string().min(1).max(2000), endDate: z.string().datetime(), categories: z.array(z.string()).min(1) }) export async function POST(request: Request) { const body = await request.json() try { const validated = CreateMarketSchema.parse(body) // Proceed with validated data } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json({ success: false, error: 'Validation failed', details: error.errors }, { status: 400 }) } } }字段约束示例展示了常用的长度边界(min(1).max(200))、日期格式(.datetime())与非空数组(array(...).min(1));校验错误对象error.errors直接返回给客户端,便于定位具体字段。五、文件组织1. 项目目录结构(Next.js App Router 示例)按职责分层组织源码,路由、组件、Hook、工具、类型、样式各归其位:src/ ├── app/ # Next.js App Router │ ├── api/ # API routes │ ├── markets/ # Market pages │ └── (auth)/ # Auth pages (route groups) ├── components/ # React components │ ├── ui/ # Generic UI components │ ├── forms/ # Form components │ └── layouts/ # Layout components ├── hooks/ # Custom React hooks ├── lib/ # Utilities and configs │ ├── api/ # API clients │ ├── utils/ # Helper functions │ └── constants/ # Constants ├── types/ # TypeScript types └── styles/ # Global styles路由组(auth)用于组织页面而不污染 URL 路径;components/ui存放通用 UI 原子组件,components/forms、components/layouts分别存放表单与布局类组件。2. 文件命名约定不同类型的文件采用不同的大小写风格,形成一眼可辨的命名规律:components/Button.tsx # PascalCase for components hooks/useAuth.ts # camelCase with 'use' prefix lib/formatDate.ts # camelCase for utilities types/market.types.ts # camelCase with .types suffix组件文件:PascalCase(Button.tsx);Hook 文件:camelCase 且带use前缀(useAuth.ts);工具函数:camelCase(formatDate.ts);类型文件:camelCase 加.types后缀(market.types.ts)。六、注释与文档规范1. 注释时机:解释 WHY,不解释 WHAT注释只用于代码无法自明的内容——原因、权衡、性能取舍:// ✅ GOOD: Explain WHY, not WHAT // Use exponential backoff to avoid overwhelming the API during outages const delay = Math.min(1000 * Math.pow(2, retryCount), 30000) // Deliberately using mutation here for performance with large arrays items.push(newItem) // ❌ BAD: Stating the obvious // Increment counter by 1 count++ // Set name to user's name name = user.name示例中的两处「好注释」都记录了代码背后的决策理由(退避策略、刻意使用可变操作),而「坏注释」只是把代码复述了一遍,属于噪音。2. 公开 API 的 JSDoc对外暴露的函数必须使用 JSDoc 三件套:@param说明参数与默认值、@returns说明返回值、@throws说明异常场景,并附带@example可运行示例:/** * Searches markets using semantic similarity. * * @param query - Natural language search query * @param limit - Maximum number of results (default: 10) * @returns Array of markets sorted by similarity score * @throws {Error} If OpenAI API fails or Redis unavailable * * @example * ```typescript * const results = await searchMarkets('election', 5) * console.log(results[0].name) // "Trump vs Biden" * ``` */ export async function searchMarkets( query: string, limit: number = 10 ): Promise<Market[]> { // Implementation }@example中的注释式输出(// "Trump vs Biden")让调用者在 IDE 中即可预览预期行为,无需跳转实现。七、性能最佳实践1. 记忆化:useMemo / useCallback昂贵计算用useMemo缓存,回调函数用useCallback稳定引用,避免子组件无谓重渲染:import { useMemo, useCallback } from 'react' // ✅ GOOD: Memoize expensive computations const sortedMarkets = useMemo(() => { return markets.sort((a, b) => b.volume - a.volume) }, [markets]) // ✅ GOOD: Memoize callbacks const handleSearch = useCallback((query: string) => { setSearchQuery(query) }, [])依赖数组必须写全([markets]/[]),否则记忆化结果会失效或使用过期数据。2. 懒加载:lazy + Suspense体积大、首屏不需要的重组件用React.lazy按需加载,配合Suspense提供加载占位:import { lazy, Suspense } from 'react' // ✅ GOOD: Lazy load heavy components const HeavyChart = lazy(() => import('./HeavyChart')) export function Dashboard() { return ( <Suspense fallback={<Spinner />}> <HeavyChart /> </Suspense> ) }3. 数据库查询:只取需要的列查询时显式列出需要的字段,禁止无脑select('*'):// ✅ GOOD: Select only needed columns const { data } = await supabase .from('markets') .select('id, name, status') .limit(10) // ❌ BAD: Select everything const { data } = await supabase .from('markets') .select('*')八、测试标准1. 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) })2. 测试命名:描述行为而非过程测试名应以「在什么条件下、发生什么结果」的句子形态书写,拒绝works这类空泛命名:// ✅ GOOD: Descriptive test names test('returns empty array when no markets match query', () => { }) test('throws error when OpenAI API key is missing', () => { }) test('falls back to substring search when Redis unavailable', () => { }) // ❌ BAD: Vague test names test('works', () => { }) test('test search', () => { })好的测试名同时起到了「行为文档」的作用:throws error when OpenAI API key is missing直接描述了依赖缺失时的契约行为,falls back to substring search when Redis unavailable则记录了降级策略。九、代码坏味道检测清单评审代码时,逐项排查以下三类高频反模式:1. 长函数(超过 50 行)超长函数应被拆分为多个职责单一的小函数,通过清晰的调用链表达流程:// ❌ BAD: Function > 50 lines function processMarketData() { // 100 lines of code } // ✅ GOOD: Split into smaller functions function processMarketData() { const validated = validateData() const transformed = transformData(validated) return saveData(transformed) }2. 深层嵌套(5 层以上)用「提前返回(early return)」拍平嵌套,把守卫条件逐个前置:// ❌ BAD: 5+ levels of nesting if (user) { if (user.isAdmin) { if (market) { if (market.isActive) { if (hasPermission) { // Do something } } } } } // ✅ GOOD: Early returns if (!user) return if (!user.isAdmin) return if (!market) return if (!market.isActive) return if (!hasPermission) return // Do something3. 魔法数字(Magic Numbers)裸数字无法表达意图,必须提取为命名常量:// ❌ BAD: Unexplained numbers if (retryCount > 3) { } setTimeout(callback, 500) // ✅ GOOD: Named constants const MAX_RETRIES = 3 const DEBOUNCE_DELAY_MS = 500 if (retryCount > MAX_RETRIES) { } setTimeout(callback, DEBOUNCE_DELAY_MS)命名常量采用UPPER_SNAKE_CASE并在名称中带上单位(_MS),让数值语义一目了然。十、在 Agent 工作流中使用本规范cc-skill-coding-standards在 AAS 技能库中的定位是通用元技能(category: meta),意味着它可叠加到任何代码生成、重构、评审任务上作为质量标准层。结合 SKILL.md 的约束,使用时请注意:触发条件:仅当任务与上述范围(TypeScript / JavaScript / React / Node.js 开发、API 设计、代码评审)明确匹配时才启用本技能,不适用于无关场景;验证前提:本规范的输出不能替代环境相关的专项验证、测试或专家评审——代码通过本清单检查后,仍需运行真实测试与构建;澄清机制:当所需的输入、权限、安全边界或成功标准缺失时,应停下并向用户澄清,而不是强行执行;加载策略:聚焦单一任务时按需加载对应章节(如只写 React 组件就加载第三节);端到端完整执行时应通读全文。仓库中同一技能同时存在于 skills/cc-skill-coding-standards 目录(技能源目录)与 plugins/agentic-awesome-skills-claude/skills/cc-skill-coding-standards(Claude 插件打包目录),两个副本的SKILL.md均指向references/detailed-guide.md作为完整规程与参考材料,根技能文件只保留激活条件、使用示例、安全约束与局限说明——这种「根文件精简 + 详细指南分卷」的结构,正是为了让 Agent 在上下文有限时也能按需加载,是阅读本仓库其他技能时值得借鉴的组织模式。小结:代码质量不是可协商项。清晰、可维护的代码是快速迭代与自信重构的前提——这正是cc-skill-coding-standards作为risk: critical技能存在的意义:它不是一份供人欣赏的文档,而是一套可以在每次提交前、每次评审中逐条对照执行的硬性检查清单。【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
agentic-awesome-skills 编码规范实战详解:覆盖 TypeScript、React、Node.js 与 API 设计的通用代码质量标准【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills本文以 AAS(agentic-awesome-skills)仓库中cc-skill-coding-standards技能的详细指南(references/detailed-guide.md)为核心骨架展开,逐节完整继承其命名规范、不可变更新、错误处理、类型安全、组件结构、API 契约、文件组织、注释、性能优化、测试与坏味道检测等全部要点,并结合 SKILL.md 的元信息与 skills_index.json 的索引记录加以佐证。读者读完后,可以把它当作一套可直接落地的「可执行编码标准清单」,在编写或评审任何 TypeScript / JavaScript / React / Node.js 项目代码时对照使用。cc-skill-coding-standards是 AAS 技能库中面向所有项目通用的编码标准类技能:它不绑定某个业务模块,而是定义了一套跨项目适用的「质量底线」。从仓库索引看,该技能被标记为category: meta、risk: critical、source: community,加入时间为2026-02-27,并在 skills_index.json 中声明对 Codex 与 Claude 两类 Agent 目标均supported(plugin.targets.codex/plugin.targets.claude均为supported)。技能根文件 SKILL.md 明确要求:在执行本技能前必须先通读详细指南,并把其中的安全前提与校验要求视为强制性约束。一、代码质量四项核心原则所有具体规范都建立在四条经典工程原则之上,它们是后续每个章节的判据来源。1. Readability First(可读性优先)代码被阅读的次数远多于被书写的次数,可读性是第一优先级;变量与函数命名必须清晰,让意图自明;优先「自文档化代码」(self-documenting code),注释只补充代码无法表达的信息;保持统一的格式化风格,减少读者切换成本。2. KISS(Keep It Simple, Stupid)选择能工作的最简单方案,而不是最「聪明」的方案;避免过度设计(over-engineering);不做过早优化(premature optimization);「易于理解」永远优于「炫技代码」。3. DRY(Don't Repeat Yourself)把公共逻辑抽取为函数;创建可复用的组件与工具模块;跨模块共享工具函数;杜绝复制粘贴式编程——每处重复都是未来 bug 的潜在来源。4. YAGNI(You Aren't Gonna Need It)不在需求到来之前预构功能;避免投机性泛化(speculative generality);只在确实需要时增加复杂度;先简单起步,需要时再重构演进。这四条原则在 AAS 技能库中被定位为risk: critical,意味着在代码生成、代码评审类工作流中,它们属于「违反即扣分」的硬性约束,而非可选项。二、TypeScript / JavaScript 编码标准1. 变量命名:描述性优于缩写使用能表达语义的完整名称,杜绝无意义的单字母或模糊布尔量:// ✅ GOOD: Descriptive names const marketSearchQuery = 'election' const isUserAuthenticated = true const totalRevenue = 1000 // ❌ BAD: Unclear names const q = 'election' const flag = true const x = 1000布尔值建议采用is/has/can等前缀(如isUserAuthenticated),数量型变量采用total/count等前缀(如totalRevenue),搜索查询等上下文型变量带上领域词(如marketSearchQuery)。2. 函数命名:动词 + 名词 模式函数名应描述「动作 + 对象」,让调用点读起来像一句自然语言:// ✅ GOOD: Verb-noun pattern async function fetchMarketData(marketId: string) { } function calculateSimilarity(a: number[], b: number[]) { } function isValidEmail(email: string): boolean { } // ❌ BAD: Unclear or noun-only async function market(id: string) { } function similarity(a, b) { } function email(e) { }同时为函数标注完整的参数类型与返回值类型(如a: number[]、: boolean),让类型成为签名的一部分。3. 不可变更新模式(CRITICAL,强制)React / Node.js 项目中对象与数组的更新必须使用展开运算符(spread)创建新引用,严禁直接修改原对象或原数组——这是避免 React 渲染失效、并发状态错乱的最关键约定:// ✅ ALWAYS use spread operator const updatedUser = { ...user, name: 'New Name' } const updatedArray = [...items, newItem] // ❌ NEVER mutate directly user.name = 'New Name' // BAD items.push(newItem) // BAD注意:新增数组元素使用[...items, newItem]生成新数组,而不是items.push(...);更新对象属性使用{ ...user, name: 'New Name' },而不是直接赋值user.name = ...。该节在原文档中被显式标注为 CRITICAL 级别,属于必须无条件遵守的硬性规则。4. 错误处理:全面捕获,绝不静默失败异步函数必须捕获网络 / 状态类错误,检查 HTTP 状态码,并向上层抛出带上下文的新错误:// ✅ GOOD: Comprehensive error handling async function fetchData(url: string) { try { const response = await fetch(url) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } return await response.json() } catch (error) { console.error('Fetch failed:', error) throw new Error('Failed to fetch data') } } // ❌ BAD: No error handling async function fetchData(url) { const response = await fetch(url) return response.json() }要点:response.ok === false时显式抛错并携带status/statusText;catch 块中先记录原始错误(console.error),再抛出对调用方有意义的封装错误,避免吞掉异常或丢失根因。5. Async / Await:能并行就不要串行互不依赖的异步任务用Promise.all并行执行,减少总等待时间:// ✅ GOOD: Parallel execution when possible const [users, markets, stats] = await Promise.all([ fetchUsers(), fetchMarkets(), fetchStats() ]) // ❌ BAD: Sequential when unnecessary const users = await fetchUsers() const markets = await fetchMarkets() const stats = await fetchStats()6. 类型安全:消灭any用接口(interface)与联合类型(union type)描述数据形状,函数签名返回强类型 Promise:// ✅ GOOD: Proper types interface Market { id: string name: string status: 'active' | 'resolved' | 'closed' created_at: Date } function getMarket(id: string): Promise<Market> { // Implementation } // ❌ BAD: Using 'any' function getMarket(id: any): Promise<any> { // Implementation }status使用字面量联合类型'active' | 'resolved' | 'closed'而非string,让非法状态在编译期即被拦截;任何any的出现都应视为技术债。三、React 最佳实践1. 组件结构:函数组件 + 完整 Props 类型组件必须使用带类型的函数组件,通过interface显式声明 Props,并给出默认值:// ✅ GOOD: Functional component with types interface ButtonProps { children: React.ReactNode onClick: () => void disabled?: boolean variant?: 'primary' | 'secondary' } export function Button({ children, onClick, disabled = false, variant = 'primary' }: ButtonProps) { return ( <button onClick={onClick} disabled={disabled} className={`btn btn-${variant}`} > {children} </button> ) } // ❌ BAD: No types, unclear structure export function Button(props) { return <button onClick={props.onClick}>{props.children}</button> }variant同样采用联合类型限定取值范围;可选 Props(disabled、variant)在解构时赋予默认值,保证组件行为可预测。2. 自定义 Hooks:封装可复用逻辑把可复用的副作用逻辑封装为use前缀的自定义 Hook,并保持泛型通用:// ✅ GOOD: Reusable custom hook export function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState<T>(value) useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value) }, delay) return () => clearTimeout(handler) }, [value, delay]) return debouncedValue } // Usage const debouncedQuery = useDebounce(searchQuery, 500)要点:useEffect的 cleanup 中调用clearTimeout防止内存泄漏;依赖数组[value, delay]保证 timer 在输入变化时重置;返回去抖后的值供组件直接消费。3. 状态管理:优先函数式更新基于前一个状态计算新状态时,使用函数式更新(setCount(prev => prev + 1)),避免异步场景中的过期闭包(stale closure):// ✅ GOOD: Proper state updates const [count, setCount] = useState(0) // Functional update for state based on previous state setCount(prev => prev + 1) // ❌ BAD: Direct state reference setCount(count + 1) // Can be stale in async scenarios4. 条件渲染:短路表达式,拒绝三元地狱加载、错误、数据三种状态分别用&&短路渲染,保持 JSX 平铺可读:// ✅ GOOD: Clear conditional rendering {isLoading && <Spinner />} {error && <ErrorMessage error={error} />} {data && <DataDisplay data={data} />} // ❌ BAD: Ternary hell {isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}四、API 设计标准1. REST 路由约定资源名使用复数名词,方法语义与 HTTP 动词一一对应:GET /api/markets # List all markets GET /api/markets/:id # Get specific market POST /api/markets # Create new market PUT /api/markets/:id # Update market (full) PATCH /api/markets/:id # Update market (partial) DELETE /api/markets/:id # Delete market # Query parameters for filtering GET /api/markets?status=active&limit=10&offset=0约定要点:PUT表示全量替换,PATCH表示局部更新;列表接口统一通过 query string 提供过滤(status)与分页(limit/offset)。2. 统一响应格式所有接口返回一致的响应信封(envelope),成功与失败路径结构对称:// ✅ GOOD: Consistent response structure interface ApiResponse<T> { success: boolean data?: T error?: string meta?: { total: number page: number limit: number } } // Success response return NextResponse.json({ success: true, data: markets, meta: { total: 100, page: 1, limit: 10 } }) // Error response return NextResponse.json({ success: false, error: 'Invalid request' }, { status: 400 })meta中携带分页元数据(total/page/limit),前端可直接渲染分页器;错误响应同时配合 HTTP 状态码(如 400)。3. 输入校验:Schema 优先使用 zod 在进入业务逻辑前完成请求体校验,失败时返回结构化错误明细:import { z } from 'zod' // ✅ GOOD: Schema validation const CreateMarketSchema = z.object({ name: z.string().min(1).max(200), description: z.string().min(1).max(2000), endDate: z.string().datetime(), categories: z.array(z.string()).min(1) }) export async function POST(request: Request) { const body = await request.json() try { const validated = CreateMarketSchema.parse(body) // Proceed with validated data } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json({ success: false, error: 'Validation failed', details: error.errors }, { status: 400 }) } } }字段约束示例展示了常用的长度边界(min(1).max(200))、日期格式(.datetime())与非空数组(array(...).min(1));校验错误对象error.errors直接返回给客户端,便于定位具体字段。五、文件组织1. 项目目录结构(Next.js App Router 示例)按职责分层组织源码,路由、组件、Hook、工具、类型、样式各归其位:src/ ├── app/ # Next.js App Router │ ├── api/ # API routes │ ├── markets/ # Market pages │ └── (auth)/ # Auth pages (route groups) ├── components/ # React components │ ├── ui/ # Generic UI components │ ├── forms/ # Form components │ └── layouts/ # Layout components ├── hooks/ # Custom React hooks ├── lib/ # Utilities and configs │ ├── api/ # API clients │ ├── utils/ # Helper functions │ └── constants/ # Constants ├── types/ # TypeScript types └── styles/ # Global styles路由组(auth)用于组织页面而不污染 URL 路径;components/ui存放通用 UI 原子组件,components/forms、components/layouts分别存放表单与布局类组件。2. 文件命名约定不同类型的文件采用不同的大小写风格,形成一眼可辨的命名规律:components/Button.tsx # PascalCase for components hooks/useAuth.ts # camelCase with 'use' prefix lib/formatDate.ts # camelCase for utilities types/market.types.ts # camelCase with .types suffix组件文件:PascalCase(Button.tsx);Hook 文件:camelCase 且带use前缀(useAuth.ts);工具函数:camelCase(formatDate.ts);类型文件:camelCase 加.types后缀(market.types.ts)。六、注释与文档规范1. 注释时机:解释 WHY,不解释 WHAT注释只用于代码无法自明的内容——原因、权衡、性能取舍:// ✅ GOOD: Explain WHY, not WHAT // Use exponential backoff to avoid overwhelming the API during outages const delay = Math.min(1000 * Math.pow(2, retryCount), 30000) // Deliberately using mutation here for performance with large arrays items.push(newItem) // ❌ BAD: Stating the obvious // Increment counter by 1 count++ // Set name to user's name name = user.name示例中的两处「好注释」都记录了代码背后的决策理由(退避策略、刻意使用可变操作),而「坏注释」只是把代码复述了一遍,属于噪音。2. 公开 API 的 JSDoc对外暴露的函数必须使用 JSDoc 三件套:@param说明参数与默认值、@returns说明返回值、@throws说明异常场景,并附带@example可运行示例:/** * Searches markets using semantic similarity. * * @param query - Natural language search query * @param limit - Maximum number of results (default: 10) * @returns Array of markets sorted by similarity score * @throws {Error} If OpenAI API fails or Redis unavailable * * @example * ```typescript * const results = await searchMarkets('election', 5) * console.log(results[0].name) // "Trump vs Biden" * ``` */ export async function searchMarkets( query: string, limit: number = 10 ): Promise<Market[]> { // Implementation }@example中的注释式输出(// "Trump vs Biden")让调用者在 IDE 中即可预览预期行为,无需跳转实现。七、性能最佳实践1. 记忆化:useMemo / useCallback昂贵计算用useMemo缓存,回调函数用useCallback稳定引用,避免子组件无谓重渲染:import { useMemo, useCallback } from 'react' // ✅ GOOD: Memoize expensive computations const sortedMarkets = useMemo(() => { return markets.sort((a, b) => b.volume - a.volume) }, [markets]) // ✅ GOOD: Memoize callbacks const handleSearch = useCallback((query: string) => { setSearchQuery(query) }, [])依赖数组必须写全([markets]/[]),否则记忆化结果会失效或使用过期数据。2. 懒加载:lazy + Suspense体积大、首屏不需要的重组件用React.lazy按需加载,配合Suspense提供加载占位:import { lazy, Suspense } from 'react' // ✅ GOOD: Lazy load heavy components const HeavyChart = lazy(() => import('./HeavyChart')) export function Dashboard() { return ( <Suspense fallback={<Spinner />}> <HeavyChart /> </Suspense> ) }3. 数据库查询:只取需要的列查询时显式列出需要的字段,禁止无脑select('*'):// ✅ GOOD: Select only needed columns const { data } = await supabase .from('markets') .select('id, name, status') .limit(10) // ❌ BAD: Select everything const { data } = await supabase .from('markets') .select('*')八、测试标准1. 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) })2. 测试命名:描述行为而非过程测试名应以「在什么条件下、发生什么结果」的句子形态书写,拒绝works这类空泛命名:// ✅ GOOD: Descriptive test names test('returns empty array when no markets match query', () => { }) test('throws error when OpenAI API key is missing', () => { }) test('falls back to substring search when Redis unavailable', () => { }) // ❌ BAD: Vague test names test('works', () => { }) test('test search', () => { })好的测试名同时起到了「行为文档」的作用:throws error when OpenAI API key is missing直接描述了依赖缺失时的契约行为,falls back to substring search when Redis unavailable则记录了降级策略。九、代码坏味道检测清单评审代码时,逐项排查以下三类高频反模式:1. 长函数(超过 50 行)超长函数应被拆分为多个职责单一的小函数,通过清晰的调用链表达流程:// ❌ BAD: Function > 50 lines function processMarketData() { // 100 lines of code } // ✅ GOOD: Split into smaller functions function processMarketData() { const validated = validateData() const transformed = transformData(validated) return saveData(transformed) }2. 深层嵌套(5 层以上)用「提前返回(early return)」拍平嵌套,把守卫条件逐个前置:// ❌ BAD: 5+ levels of nesting if (user) { if (user.isAdmin) { if (market) { if (market.isActive) { if (hasPermission) { // Do something } } } } } // ✅ GOOD: Early returns if (!user) return if (!user.isAdmin) return if (!market) return if (!market.isActive) return if (!hasPermission) return // Do something3. 魔法数字(Magic Numbers)裸数字无法表达意图,必须提取为命名常量:// ❌ BAD: Unexplained numbers if (retryCount > 3) { } setTimeout(callback, 500) // ✅ GOOD: Named constants const MAX_RETRIES = 3 const DEBOUNCE_DELAY_MS = 500 if (retryCount > MAX_RETRIES) { } setTimeout(callback, DEBOUNCE_DELAY_MS)命名常量采用UPPER_SNAKE_CASE并在名称中带上单位(_MS),让数值语义一目了然。十、在 Agent 工作流中使用本规范cc-skill-coding-standards在 AAS 技能库中的定位是通用元技能(category: meta),意味着它可叠加到任何代码生成、重构、评审任务上作为质量标准层。结合 SKILL.md 的约束,使用时请注意:触发条件:仅当任务与上述范围(TypeScript / JavaScript / React / Node.js 开发、API 设计、代码评审)明确匹配时才启用本技能,不适用于无关场景;验证前提:本规范的输出不能替代环境相关的专项验证、测试或专家评审——代码通过本清单检查后,仍需运行真实测试与构建;澄清机制:当所需的输入、权限、安全边界或成功标准缺失时,应停下并向用户澄清,而不是强行执行;加载策略:聚焦单一任务时按需加载对应章节(如只写 React 组件就加载第三节);端到端完整执行时应通读全文。仓库中同一技能同时存在于 skills/cc-skill-coding-standards 目录(技能源目录)与 plugins/agentic-awesome-skills-claude/skills/cc-skill-coding-standards(Claude 插件打包目录),两个副本的SKILL.md均指向references/detailed-guide.md作为完整规程与参考材料,根技能文件只保留激活条件、使用示例、安全约束与局限说明——这种「根文件精简 + 详细指南分卷」的结构,正是为了让 Agent 在上下文有限时也能按需加载,是阅读本仓库其他技能时值得借鉴的组织模式。小结:代码质量不是可协商项。清晰、可维护的代码是快速迭代与自信重构的前提——这正是cc-skill-coding-standards作为risk: critical技能存在的意义:它不是一份供人欣赏的文档,而是一套可以在每次提交前、每次评审中逐条对照执行的硬性检查清单。【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考