尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ECC coding-standards 技能详解:TypeScript、React 与 API 设计的跨项目编码规范

ECC coding-standards 技能详解:TypeScript、React 与 API 设计的跨项目编码规范 ECC coding-standards 技能详解TypeScript、React 与 API 设计的跨项目编码规范【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECCECCThe agent harness performance optimization system将一套通用的 TypeScript/JavaScript、React 与 Node.js 编码规范封装为 Kiro 平台的按需技能coding-standards安装到项目后可通过聊天/菜单直接调用用于代码审查、新模块起步和团队规范落地。本文完整拆解该技能的规范体系——四大质量原则、命名与不可变性准则、React 与 API 设计标准、性能与测试规范、代码坏味道检测清单——并结合 ECC 仓库中的规则层文件与 ESLint 配置说明这些规范如何在工程中真正被约束和验证。读完后你既能把这份规范直接套用到自己的 TS/React 项目中也能理解它在 ECC 分层体系中的定位与配套落地手段。一、coding-standards 是什么Kiro 技能机制与激活时机该技能定义在.kiro/skills/coding-standards/SKILL.md文件以 YAML frontmatter 声明元数据--- name: coding-standards description: Universal coding standards, best practices, and patterns for TypeScript, JavaScript, React, and Node.js development. metadata: origin: ECC ---根据.kiro/README.md的说明.kiro/skills/目录下共安装了 43 个技能它们是“可经由聊天/菜单按需调用的工作流”Skills are on-demand workflows invocable via the/menu in chat。每个技能都是一个包含SKILL.md的目录frontmatter 中的name决定菜单中的可调用名称description决定其语义边界。因此开发者在 Kiro 中输入/并选择coding-standards即可让 Agent 以这份规范为审查/编码基准开展工作。技能文档同时明确了激活场景When to Activate即这份规范适用于以下六类工作启动新项目或新模块以质量与可维护性为目标审查代码重构既有代码以符合约定强制执行命名、格式或结构一致性配置 lint、格式化或类型检查规则帮助新贡献者了解编码约定需要注意技能的范围定位。ECC 主仓中对应的基线版技能skills/coding-standards/SKILL.md在 frontmatter 之后额外给出了明确的边界说明它是“共享的底线而非详细框架手册”the shared floor, not the detailed framework playbook——React 组合、hooks、渲染与 UI 架构问题应使用frontend-patterns后端架构、API 设计、数据库分层应使用backend-patterns或api-design只需要最短可复用规则层时应参考rules/common/coding-style.md。这种“技能管完整流程、规则管最小约束”的分层设计是 ECC 规范体系的一个重要特征后文第四节会结合具体文件展开。二、代码质量四原则Readability、KISS、DRY、YAGNI技能的第一部分确立了四条贯穿全部后续规范的质量原则理解它们是读懂其余条款的钥匙。1. Readability First可读性优先代码被阅读的次数远多于被编写的次数变量与函数命名必须清晰自解释代码优于注释保持格式一致2. KISSKeep It Simple, Stupid采用能工作的最简单方案避免过度设计不做过早优化易理解的代码 炫技的代码3. DRYDont Repeat Yourself将公共逻辑提取为函数创建可复用组件跨模块共享工具杜绝复制粘贴式编程4. YAGNIYou Arent Gonna Need It不提前构建尚不需要的功能避免臆测性泛化speculative generality仅在确有需求时引入复杂度从简单开始必要时再重构ECC 的规则层文件rules/common/coding-style.md将这同一套原则压缩成了更短的可复用表述例如 DRY 条目补充了一条实践判断标准“Introduce abstractions when repetition is real, not speculative”当重复是真实存在的而非臆测时才引入抽象YAGNI 条目则强调 “Start simple, then refactor when the pressure is real”从简单开始等压力真实到来时再重构。技能版讲“何时激活什么行为”规则版给“最短可执行判据”两者互为表里。三、TypeScript/JavaScript 规范命名、不可变性、错误处理与类型安全这是技能的核心章节全部采用 PASS/FAIL 对照代码示例可直接作为代码审查清单使用。3.1 变量命名描述性名称// PASS: GOOD: Descriptive names const marketSearchQuery election const isUserAuthenticated true const totalRevenue 1000 // FAIL: BAD: Unclear names const q election const flag true const x 1000要点布尔变量使用is/has/should/can前缀表达语义isUserAuthenticated名称应承载业务含义而非缩写。3.2 函数命名动词-名词模式// PASS: GOOD: Verb-noun pattern async function fetchMarketData(marketId: string) { } function calculateSimilarity(a: number[], b: number[]) { } function isValidEmail(email: string): boolean { } // FAIL: BAD: Unclear or noun-only async function market(id: string) { } function similarity(a, b) { } function email(e) { }纯名词market、email无法表达函数“做什么”应统一采用fetchMarketData、calculateSimilarity这类动词-名词结构并在参数与返回值上补全类型。3.3 不可变性模式技能标记为 CRITICAL// PASS: ALWAYS use spread operator const updatedUser { ...user, name: New Name } const updatedArray [...items, newItem] // FAIL: NEVER mutate directly user.name New Name // BAD items.push(newItem) // BAD这是技能中唯一被标注为 “CRITICAL” 的条目。ECC 的规则层对此给出了统一的伪代码判据见rules/common/coding-style.mdWRONG: modify(original, field, value) → changes original in-place CORRECT: update(original, field, value) → returns new copy with change其理由写明不可变数据可防止隐藏副作用、让调试更容易、并支持安全的并发。值得注意的是技能允许有意识地违反这一默认值但必须在注释中说明原因——注释规范章节第六节的示例正是如此// Deliberately using mutation here for performance with large arrays配合items.push(newItem)。规则是默认值带理由的例外优于无理由的遵守。3.4 错误处理全面而非缺失// PASS: 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) } } // FAIL: BAD: No error handling async function fetchData(url) { const response await fetch(url) return response.json() }模式拆解先用response.ok拦截 HTTP 层失败并抛出自带状态码的明确错误再在catch中记录详细上下文console.error带原始 error 对象并向上传播精简后的错误消息。这与规则层“错误处理”章节的四条要求一一对应每一层显式处理、面向 UI 的代码提供用户友好消息、服务端记录详细上下文、绝不静默吞错Never silently swallow errors。3.5 Async/Await能并行就并行// PASS: GOOD: Parallel execution when possible const [users, markets, stats] await Promise.all([ fetchUsers(), fetchMarkets(), fetchStats() ]) // FAIL: BAD: Sequential when unnecessary const users await fetchUsers() const markets await fetchMarkets() const stats await fetchStats()无依赖关系的多个异步调用应使用Promise.all并发执行串行await会把总耗时累加为各请求之和。3.6 类型安全拒绝any// PASS: GOOD: Proper types interface Market { id: string name: string status: active | resolved | closed created_at: Date } function getMarket(id: string): PromiseMarket { // Implementation } // FAIL: BAD: Using any function getMarket(id: any): Promiseany { // Implementation }示例中status字段使用字符串字面量联合active | resolved | closed而非enum与 ECC 的 TypeScript 规则层rules/typescript/coding-style.md的建议一致对象形状用interface可被扩展/实现联合、交叉、元组与工具类型用type并优先字符串字面量联合代替enum。该规则文件还进一步给出any的替代路径——对外部/不可信输入使用unknown再安全收窄// CORRECT: unknown forces safe narrowing function getErrorMessage(error: unknown): string { if (error instanceof Error) { return error.message } return Unexpected error }该规则文件顶部带有pathsfrontmatter**/*.ts、**/*.tsx、**/*.js、**/*.jsx说明 ECC 的规则按 glob 路径条件注入——这正是“规则管最小约束、按文件类型生效”的实现方式。四、React 最佳实践组件、Hooks、状态与条件渲染4.1 组件结构函数式组件 显式 Props 类型// PASS: 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 ) } // FAIL: BAD: No types, unclear structure export function Button(props) { return button onClick{props.onClick}{props.children}/button }示例涵盖了技能隐含的组件四要素命名interface定义 Props而非React.FC规则层明确 “Do not useReact.FCunless there is a specific reason”、解构 默认值参数、回调属性显式类型、variant用字面量联合收敛取值范围。4.2 自定义 Hooks可复用的防抖示例// PASS: GOOD: Reusable custom hook export function useDebounceT(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] useStateT(value) useEffect(() { const handler setTimeout(() { setDebouncedValue(value) }, delay) return () clearTimeout(handler) }, [value, delay]) return debouncedValue } // Usage const debouncedQuery useDebounce(searchQuery, 500)实现要点泛型T使 hook 适用于任意值类型useEffect依赖[value, delay]清理函数clearTimeout保证值变化时旧定时器不残留——这是手写防抖 hook 最容易漏掉的一环。4.3 状态管理函数式更新// PASS: GOOD: Proper state updates const [count, setCount] useState(0) // Functional update for state based on previous state setCount(prev prev 1) // FAIL: BAD: Direct state reference setCount(count 1) // Can be stale in async scenariossetCount(count 1)读取的是当前渲染周期的闭包值在事件循环、异步回调或连续触发场景下可能拿到过期状态setCount(prev prev 1)始终基于最新状态计算应作为默认写法。4.4 条件渲染拒绝三目嵌套地狱// PASS: GOOD: Clear conditional rendering {isLoading Spinner /} {error ErrorMessage error{error} /} {data DataDisplay data{data} /} // FAIL: BAD: Ternary hell {isLoading ? Spinner / : error ? ErrorMessage error{error} / : data ? DataDisplay data{data} / : null}短路与并列布尔表达式比多层嵌套三目更易读、更易局部修改isLoading Spinner /这类写法在三个状态互斥时同样成立假值不渲染任何有意义的东西。五、API 设计标准REST 约定、统一响应格式与 Zod 校验5.1 REST 资源路由约定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?statusactivelimit10offset0资源用名词复数、全量/部分更新分别用PUT/PATCH、过滤与分页走查询参数status/limit/offset——这是与响应结构中meta.total/page/limit字段相互呼应的分页契约。5.2 统一响应结构// PASS: GOOD: Consistent response structure interface ApiResponseT { 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 })泛型ApiResponseT让每个端点复用同一信封成功时success: true携带data分页接口附带meta失败时success: false携带error字符串并配正确的 HTTP 状态码。前端因此只需一套解包逻辑即可处理所有端点。5.3 输入校验Zod Schema 在系统边界拦截import { z } from zod // PASS: 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 } } } }要点Schema 即接口契约长度限制min/max、ISO 日期校验z.string().datetime()、非空数组min(1)parse失败时返回400并回传校验详情让调用方一次修全。这一点与规则层“输入校验”章节的边界原则直接对应“ALWAYS validate at system boundaries”“Never trust external data (API responses, user input, file content)”——外部数据在边界处校验失败要快速失败Fail fast并给出清晰错误消息。一个小的版本差异值得留意ECC 主仓的基线版技能skills/coding-standards/SKILL.md在同一段示例中回传的是error.issues较新 Zod 版本的属性名而 Kiro 版使用error.errors——实际项目中以所用 Zod 版本的 API 为准即可两者语义相同。六、文件组织与命名约定6.1 项目结构以 Next.js App Router 为例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结构逻辑是按职责分层app/只放路由含(auth)这类不产生 URL 段的 route groupcomponents/再按 ui/forms/layouts 细分子类lib/按 api/utils/constants 归拢基础设施types/集中共享类型。6.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便于检索与自动导入hook 文件以use前缀保持与函数命名一致纯类型文件用.types.ts后缀区分“只含类型”与“含实现”的文件。规则层rules/common/coding-style.md对“文件多大算大”给出了量化标准可作为上述结构的补充判据MANY SMALL FILES FEW LARGE FILES高内聚低耦合源文件典型规模 200–400 行800 行为可维护性的软上限测试、生成与 vendored 文件因职责所需可豁免按 feature/domain 组织而非按 type 组织七、注释与文档解释 WHY 而非 WHAT7.1 何时该写注释// PASS: 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) // FAIL: BAD: Stating the obvious // Increment counter by 1 count // Set name to users name name user.name两条正例展示了注释的合法用途一是解释非显而易见的设计动机指数退避避免故障期压垮 API并内嵌了 30 秒上限Math.min(..., 30000)二是为“故意违反默认规则”第三节中的不可变性提供豁免理由。反例则是复述代码字面行为的无效注释。7.2 公共 API 的 JSDoc/** * 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 ): PromiseMarket[] { // Implementation }公共函数的 JSDoc 模板包含五个要素功能一句话、每个param的含义与默认值、returns的排序/形状约定、throws的失败条件、example可运行示例。规则层补充了一条面向纯 JS 项目的实践在.js/.jsx文件中当 TypeScript 迁移不现实时用 JSDoc 表达类型且必须与运行时行为保持一致“Keep JSDoc aligned with runtime behavior”。八、性能最佳实践记忆化、懒加载与查询裁剪8.1 记忆化Memoizationimport { useMemo, useCallback } from react // PASS: GOOD: Memoize expensive computations // Copy before sorting - Array.prototype.sort mutates in place const sortedMarkets useMemo(() { return [...markets].sort((a, b) b.volume - a.volume) }, [markets]) // PASS: GOOD: Memoize callbacks const handleSearch useCallback((query: string) { setSearchQuery(query) }, [])注意[...markets].sort(...)这一细节Array.prototype.sort原地修改数组直接对状态数组排序既违反不可变性原则第三节 CRITICAL 条目又会触发难以追踪的状态污染因此注释先声明 “Copy before sorting” 再展开拷贝。这展示了技能内部各章节的交叉引用——性能优化代码同样受不可变性约束。8.2 懒加载重型组件import { lazy, Suspense } from react // PASS: GOOD: Lazy load heavy components const HeavyChart lazy(() import(./HeavyChart)) export function Dashboard() { return ( Suspense fallback{Spinner /} HeavyChart / /Suspense ) }lazy 动态import()将重图表拆成独立 chunkSuspense的 fallback 与第四节条件渲染的Spinner /复用同一组件保持加载态视觉一致。8.3 数据库查询只取需要的列// PASS: GOOD: Select only needed columns const { data } await supabase .from(markets) .select(id, name, status) .limit(10) // FAIL: BAD: Select everything const { data } await supabase .from(markets) .select(*)列裁剪 limit是最基础的传输层优化与第五节分页契约limit/offset保持一致API 层约定分页参数查询层必须兑现。九、测试标准AAA 结构与描述性命名9.1 AAA 模式Arrange–Act–Asserttest(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) })测试体固定分三段准备输入含正交的向量 1 与向量 2、执行单一被测调用、断言精确结果。正交向量余弦相似为 0使断言值本身可手工验证。9.2 测试命名描述“场景-行为”// PASS: 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, () { }) // FAIL: BAD: Vague test names test(works, () { }) test(test search, () { })正例遵循 “行为 when 条件” 句式覆盖边界无匹配、故障密钥缺失与降级Redis 不可用回退三类场景测试名本身就是文档失败日志能直接定位问题。十、代码坏味道检测三类反模式的量化判据技能将坏味道检查收敛为三类且都给出了可量化的重构手法。10.1 长函数超过 50 行// FAIL: BAD: Function 50 lines function processMarketData() { // 100 lines of code } // PASS: GOOD: Split into smaller functions function processMarketData() { const validated validateData() const transformed transformData(validated) return saveData(transformed) }重构模式是“管道式分解”原函数退化为 validate → transform → save 三步编排每步独立命名、可单独测试。规则层将此量化为 checklist 项 “Functions are small (50 lines)”。10.2 深层嵌套5 层以上// FAIL: BAD: 5 levels of nesting if (user) { if (user.isAdmin) { if (market) { if (market.isActive) { if (hasPermission) { // Do something } } } } } // PASS: GOOD: Early returns if (!user) return if (!user.isAdmin) return if (!market) return if (!market.isActive) return if (!hasPermission) return // Do something守卫子句guard clause把 5 层嵌套压平成 5 个线性早退主逻辑的缩进深度归零。规则层 checklist 对应项为 “No deep nesting (4 levels)”。10.3 魔法数字// FAIL: BAD: Unexplained numbers if (retryCount 3) { } setTimeout(callback, 500) // PASS: GOOD: Named constants const MAX_RETRIES 3 const DEBOUNCE_DELAY_MS 500 if (retryCount MAX_RETRIES) { } setTimeout(callback, DEBOUNCE_DELAY_MS)命名常量的关键在语义命名MAX_RETRIES表达“上限”DEBOUNCE_DELAY_MS表达“防抖延迟”且带单位后缀MS。规则层 checklist 对应项为 “No hardcoded values (use constants or config)”并补充了命名规范总表变量/函数camelCase、布尔值is/has/should/can前缀、接口/类型/组件PascalCase、常量UPPER_SNAKE_CASE、hookuse前缀。技能文末的收束句值得原样引用“Code quality is not negotiable. Clear, maintainable code enables rapid development and confident refactoring.”——代码质量不可妥协清晰可维护的代码换来的是快速开发与可信赖的重构。十一、从源码结构看规范如何被 ECC 工程化地执行前述规范不是孤立文档。结合仓库中的实际文件可以看出 ECC 用一个“三层执行体系”把 coding-standards 技能从文本变成约束第一层技能层完整流程。.kiro/skills/coding-standards/SKILL.mdKiro 版与skills/coding-standards/SKILL.md主仓基线版承载本文正文的全部规范内容。主仓版额外增加的 “Scope Boundaries” 小节明确了技能的激活面描述性命名、不可变默认值、KISS/DRY/YAGNI 执行、错误处理与坏味道审查与非激活面React 组合、后端分层、已有更窄技能覆盖的框架指导防止通用技能被误用于它不该主导的场景。第二层规则层按路径注入的最小约束。rules/common/coding-style.md是跨语言通用规则含 800 行文件软上限、200–400 行典型规模、代码质量 checklistrules/typescript/coding-style.md通过pathsfrontmatter 声明只对**/*.ts、**/*.tsx、**/*.js、**/*.jsx生效补充了技能中示例背后的成文规则——interface vs type 的取舍、unknown替代any的安全收窄、React Props 禁用React.FC、JS 文件 JSDoc 与运行时对齐等。从源码结构看这种 “common 打底 语言包叠加” 的组织方式让同一套原则可以按文件类型精准生效而不需要把全部规范塞进每个技能。第三层工具层可机检的兜底。仓库根目录的 eslint.config.js 展示了技能中“配置 lint 规则”这一激活场景在 ECC 自身工程里的落地形态——flat config 下ecmaVersion: 2022默认 CommonJS、.mjs文件切换为 module引入eslint/js的 recommended 基线no-unused-vars提升为error但通过argsIgnorePattern: ^_、varsIgnorePattern: ^_、caughtErrorsIgnorePattern: ^_允许下划线前缀的刻意未用变量/参数/捕获错误——这与技能注释规范中“有理由的例外要显式声明”的精神一致用命名约定把例外白名单化no-undef: error堵住未定义引用eqeqeq: warn提示用严格相等。此外.kiro安装目录下还配套了审查类代理如.kiro/agents/typescript-reviewer.md、.kiro/agents/react-reviewer.md与技能同属一个生态技能负责在开发/审查时注入规范reviewer 代理负责按规范执行审查。适用前提与限制该技能面向TypeScript/JavaScript、React 与 Node.js技术栈frontmatter description 明确示例大量使用 Next.jsNextResponse、App Router与 Supabase 客户端若项目栈不同示例的载体 API 需替换但原则与结构命名、不可变性、响应信封、Zod 边界校验、AAA 测试是框架无关的。技能中的量化阈值函数 50 行、嵌套 4 层即坏味道、文件 800 行软上限来自 ECC 规则层的团队约定属于建议性判据而非硬约束可按团队规模调整。Kiro 侧的调用前提是项目已通过.kiro安装器完成技能安装/菜单可见frontmatter 中origin: ECC标记了技能来源谱系便于在多技能环境中溯源。小结coding-standards技能的完整脉络可以概括为四大原则Readability/KISS/DRY/YAGNI定方向 → TS/JS 规范描述性命名、CRITICAL 级不可变性、全面错误处理、Promise.all并行、拒绝any定日常写法 → React 与 API 标准显式 Props、函数式状态更新、统一响应信封、Zod 边界校验定系统形态 → 文件组织与注释规范按职责分层、WHY 注释、五要素 JSDoc定协作界面 → 性能与测试实践拷贝后排序、懒加载、列裁剪、AAA 与场景化测试名定质量下限 → 三类坏味道的量化判据50 行、4 层、命名常量定审查清单。再叠加 ECC 仓库中“技能—规则—ESLint”三层执行体系这份文档从“写给 Agent 看的规范”变成了“人、Agent 与工具共同遵守的工程契约”。将其安装进自己的 TypeScript/React 项目后最先值得落地的三件事是把不可变性设为代码审查的一票否决项、在系统边界引入 Schema 校验、并用 rules/common/coding-style.md 末尾的 checklist 作为每次提交前的自检清单。【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表