ECC 的 Cursor 规则体系:TypeScript/JavaScript 模式规则(.cursor/rules/typescript-patterns.md)深度解析
2026/9/7 7:22:51 网站建设 项目流程

ECC 的 Cursor 规则体系:TypeScript/JavaScript 模式规则(.cursor/rules/typescript-patterns.md)深度解析

【免费下载链接】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

本文以 ECC 仓库中的 Cursor 规则文件 .cursor/rules/typescript-patterns.md 为主体,完整剖析这份规则的加载机制(frontmatter 元数据)及其携带的三大 TypeScript/JavaScript 核心模式:统一 API 响应信封ApiResponse<T>、自定义 Hook 模式(以useDebounce为例)与 Repository 数据访问模式。读完后,你将理解 ECC 如何为 AI 编码助手注入项目级编码约束,并能在自己的 Cursor 项目中复制这套规则落地方式。

规则文件定位:ECC 为 Cursor 注入的 TS/JS 编码约束

.cursor/rules/typescript-patterns.md是 ECC 面向 Cursor 客户端提供的规则(Rules)文件。规则文件的头部 frontmatter 决定了 Cursor 在何时加载它:

--- description: "TypeScript patterns extending common rules" globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"] alwaysApply: false ---

三个元数据字段的含义:

  • description:规则的简短说明,供 Cursor 在规则列表与上下文匹配时参考;
  • globs:文件匹配模式。只有当会话涉及**/*.ts**/*.tsx**/*.js**/*.jsx中的文件时,该规则才会被注入上下文。这是典型的"按需加载"设计,避免在所有对话中消耗 token;
  • alwaysApply: false:明确声明该规则不是全局常驻规则,必须由 glob 命中后触发。与之对应,ECC 在 Cursor 目录下为每种语言维护了同构的 5 个文件(以 TypeScript 为例,见 .cursor/rules/ 目录:typescript-coding-style.mdtypescript-patterns.mdtypescript-hooks.mdtypescript-security.mdtypescript-testing.md),全部采用相同的 glob 作用域策略。

文件正文的开头声明:

This file extends the common patterns rule with TypeScript/JavaScript specific content.

即该文件是"通用模式规则 + 语言特化扩展"结构中的一层。对应的通用层在仓库根目录的 rules/common/patterns.md 中,语言特化层则同时存在两份镜像:

文件frontmatter 格式服务的客户端
.cursor/rules/typescript-patterns.mdglobs+alwaysApplyCursor
rules/typescript/patterns.mdpathsClaude Code / AGENTS 风格的规则加载器

两份文件正文内容完全一致(三个模式、三段代码),差异仅在 frontmatter 的键名——Cursor 使用globs/alwaysApply,而 Claude 侧使用paths。这说明 ECC 的规则体系是"内容一份、方言多份":同一套模式约束被翻译成不同 AI 客户端的规则语法后分别投放。

模式一:统一 API 响应格式(ApiResponse<T>)

原文档给出的核心类型定义:

interface ApiResponse<T> { success: boolean data?: T error?: string meta?: { total: number page: number limit: number } }

这是一个泛型响应信封(envelope),所有 API 端点共用同一结构。逐字段拆解:

  • success: boolean(必填):成功/失败指示位。客户端先判断它,再决定走data还是error分支,无需依赖 HTTP 状态码做业务级判断;
  • data?: T(可选):业务负载。错误路径下可以为null/缺省,泛型参数T让每个端点拥有独立的负载类型推断;
  • error?: string(可选):错误信息。成功路径下缺省。字符串形式意味着面向客户端的友好文案,而非原始堆栈;
  • meta?(可选):分页元信息三元组——total(总条数)、page(当前页码)、limit(每页条数)。只有列表类接口需要携带,因此整体标记为可选。

这套约定与 ECC 通用层规则严格对齐。rules/common/patterns.md 中 "API Response Format" 一节给出四条设计原则,TypeScript 版本正是其落地:

  1. 包含成功/状态指示符(对应success);
  2. 数据负载在错误时可空(对应data?);
  3. 错误信息字段在成功时可空(对应error?);
  4. 分页响应携带totalpagelimit元数据(对应meta)。

从仓库的其他规则文件看,同一信封概念在 Java、Rust、C# 的 patterns 规则(如 rules/java/patterns.md、rules/rust/patterns.md、rules/csharp/patterns.md)中都有对应表述,说明ApiResponse是 ECC 跨语言 API 设计规范的公共底座。更完整的 REST 设计规范(资源命名、状态码、分页、版本化)则可参见 skills/api-design/SKILL.md,该技能定义了200/201/204状态码语义、/api/v1/resources的 URL 结构与分页查询参数约定,与meta字段的page/limit直接呼应。

实战写法:实现端在控制器/路由层统一包装返回值,例如列表端点:

export function listUsers(page: number, limit: number) { return { success: true, data: users, meta: { total, page, limit } } }

失败路径则返回{ success: false, error: 'Detailed user-friendly message' }——这里的错误文案风格与同目录的 typescript-coding-style.md 中 "Error Handling" 一节的要求(throw new Error('Detailed user-friendly message'))保持一致。

模式二:自定义 Hooks 模式(useDebounce 示例)

原文档给出的通用 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 }

这是 React 函数组件中"把一段可复用的有状态逻辑从组件中抽出"的标准范式。要点逐条说明:

  1. 泛型签名useDebounce<T>(value: T, delay: number): T:返回值类型与入参value一致,保证useDebounce(input, 300)后仍能得到与原输入相同类型的值,类型信息无损;
  2. useState<T>(value)初始化:防抖值初始等于原值,避免首帧空值;
  3. useEffect内的定时器 + 清理函数:每次valuedelay变化都会先执行上次 effect 的清理(clearTimeout),再启动新的setTimeout。这保证了快速连续输入时只有最后一次值会在delay毫秒后生效——这正是"防抖"语义的实现核心;
  4. 依赖数组[value, delay]:只跟踪这两个输入,setDebouncedValue由 React 保证稳定,无需列入。

使用方式(以搜索框输入为例):

const query = useDebounce(rawInput, 300) useEffect(() => { if (query) search(query) }, [query])

同一模式在仓库中被反复引用和扩展:skills/frontend-patterns/SKILL.md、skills/react-patterns/SKILL.md、rules/react/hooks.md 等文件均包含useDebounce相关约定。可以推断,.cursor/rules/typescript-patterns.md中的这一节是"前端模式技能包"在 Cursor 规则侧的最小化投影——只保留一个足够典型、类型标注完整的范例,供 AI 助手在生成新 Hook 时模仿其结构(泛型参数、state + effect 组合、清理函数、依赖数组)。

模式三:Repository 数据访问模式

原文档给出的接口定义:

interface Repository<T> { findAll(filters?: Filters): Promise<T[]> findById(id: string): Promise<T | null> create(data: CreateDto): Promise<T> update(id: string, data: UpdateDto): Promise<T> delete(id: string): Promise<void> }

这是一组以实体类型T为泛型参数的标准 CRUD 契约。各方法的返回类型设计值得注意:

  • findAll(filters?):过滤条件可选,省略时返回全量;始终返回数组而非null
  • findById返回Promise<T | null>:显式把"查不到"建模进类型,调用方必须处理null分支,而不是依赖抛异常;
  • create/update返回创建/更新后的实体Promise<T>:调用方无需二次查询即可拿到最新状态;
  • update(id, data: UpdateDto)create(data: CreateDto)使用不同的 DTO:从参数命名看,创建与更新走两套载荷定义,避免"更新接口误收创建字段"这类契约错误;
  • delete返回Promise<void>:删除成功即确认,无需返回负载。

通用层 rules/common/patterns.md 对该模式的定位是:"Encapsulate data access behind a consistent interface",并给出四条原则:

  1. 定义标准操作集:findAllfindByIdcreateupdatedelete——与上面的接口签名一一对应;
  2. 具体实现处理存储细节(数据库、API、文件等);
  3. 业务逻辑只依赖抽象接口,不依赖存储机制;
  4. 便于替换数据源,并简化测试中的 mock 构造。

第 4 条是 Repository 模式在 AI 辅助开发中的关键收益:当业务函数依赖的是Repository<T>接口而非具体 ORM 时,测试中注入内存实现或 stub 即可,不需要真实数据库。例如一个依赖接口的服务函数可以写成:

export async function getUserName(repo: Repository<User>, id: string) { const user = await repo.findById(id) if (!user) throw new Error('User not found') return user.name }

测试只需提供一个findById返回预设对象的假实现,无需触碰真实存储——这正是接口Promise<T | null>返回类型让"未找到"分支可测试的原因。

三层扩展关系与规则体系中的位置

把这份规则放回 ECC 整体结构中,可以看到清晰的"通用 → 语言 → 客户端"三层投放关系:

  1. 通用层:rules/common/patterns.md 定义 Repository 模式与 API 响应信封的语言无关原则,同时包含 "Skeleton Projects" 等通用工程策略;
  2. 语言层:rules/typescript/patterns.md 将上述原则翻译为 TypeScript 代码形态(ApiResponse<T>useDebounceRepository<T>),frontmatter 使用paths键匹配**/*.{ts,tsx,js,jsx}
  3. 客户端层:.cursor/rules/typescript-patterns.md 内容与语言层逐字一致,frontmatter 换成 Cursor 的globs+alwaysApply方言。

配套的部署脚手架位于 scaffolds/cursor/ 目录(含hooks.jsonecc-agent-data.json)。其中 scaffolds/cursor/ecc-agent-data.json 声明agentDataHome: "~/.cursor/ecc",并说明 "ECC agent data root for this project when using Cursor. Memory hooks read session summaries and learned skills from here instead of ~/.claude."——即规则文件负责约束代码生成,而 Cursor 侧的 hooks 与记忆数据则路由到独立的~/.cursor/ecc目录,二者分工明确。

此外,.cursor/rules/目录中的typescript-coding-style.md与本文件互补:coding-style 管"怎么写"(不可变更新用 spread、async/await+try-catch、Zod 校验、禁用console.log),patterns 管"怎么组织"(响应信封、Hook、Repository)。两者共享同一 glob 作用域,会在处理 TS/JS 文件时同时生效。

如何在自己的项目中复用

由于该规则文件是自包含的 Markdown(无外部依赖),在任意 Cursor 项目中复用只需:

  1. 在仓库根目录创建.cursor/rules/目录;
  2. 放入本文件(或改写 frontmatter 中的globs以匹配项目实际使用的文件扩展名);
  3. 确保alwaysApply: false保持按需加载;若希望所有对话都遵守这三个模式,可改为true,但会持续占用上下文。

三个模式之间也存在协作关系:控制器按ApiResponse<T>返回数据、业务层通过Repository<T>取数、前端用useDebounce控制请求频率,恰好构成一个完整的前后端数据流闭环。这份规则文件的价值不在于三段代码本身,而在于它展示了 ECC 的通用做法——用"一小段类型完整、可直接复制的类型定义或实现"作为 AI 助手的模式模板,配合 glob 作用域实现低 token 成本的按需约束注入。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询