# CODING.md — 个人编码规范(固定资产) > 适用于本仓库所有 TS / JS 代码。人与 Agent 共同遵守,改代码前先读此文件。 ## 1. 注释规范(强制) - **强制写注释**:所有导出函数、接口 / 类型、非平凡内部函数必须有注释;无注释的导出视为未完成。 - **语言**:注释一律中文(标识符、命令、路径除外)。 - **函数级**:`/*** 作用 ***/` 置于函数 / 方法上方,一句话讲清"做什么",必要时补一句"返回什么";不复述签名、不写废话。 - **类型 / 接口**:`/*** 用途 ***/` 单行置于上方。 - **逐字段**:接口 / 类型别名每个字段都在行尾跟一句 `// 注释`,包括联合类型的每个分支。 - **行级**:其他说明用 `// 短注释` 写在行尾,只解释"为什么"或标注关键分支意图;禁止流水账、禁止翻译代码。 ```ts /*** 值比较:数值按大小、其余按字符串序,null 恒排末尾 ***/ function compareValues(a: unknown, b: unknown): number { if (a == null) return 1; // 卫语句:空值排后 if (typeof a === 'number') return a - (b as number); return String(a).localeCompare(String(b)); } /*** 一条排序规则 ***/ export interface SortRule { key: string; // 排序字段,对应 ColumnDef.key dir: 'asc' | 'desc'; // 排序方向 } ``` ## 2. 类型工程化 - **与项目平行**:类型集中放在与源码目录平行的类型文件(如 `src/types.ts`),与实现文件镜像对应;类型不散落在实现文件里。 - **紧凑**:每行一个字段(或一个联合分支),不留空行;简单接口可整体单行。 - **逐字段注释**:见上,字段注释写清"是什么、什么语义、缺省行为"。 - **命名一致**:`*Options`(入参)/ `*State`(状态)/ `*Plugin`(插件)/ `*Info`(派生快照),同类东西同名后缀,方便统一改动。 ## 3. 变量与状态声明 - **集中顶部、显式声明**:模块级 / 闭包级状态(缓存、计数器、句柄)集中在作用域顶部声明;函数内变量也尽量集中顶部。 - 仅单个分支内部使用的临时变量允许就近声明,但禁止跨分支复用"就近变量"。 - 禁止隐式全局、禁止"用到才顺手声明"的散落写法——统一管理的前提是声明可一眼盘点。 ```ts let lastInput: RowModel | null = null; // memo:上一次输入 let lastRules: SortRule[] | null = null; // memo:上一次排序切片 let cached: RowModel | null = null; // memo:缓存产物 ``` ## 4. 代码风格 - **紧凑 + 行工整**:能一行写清就一行;同构代码块(平行赋值、字段表)纵向对齐。 - **卫语句单行**:`if (!x) return;` 提前返回;嵌套超过两层必须提前返回或提取小函数。 - **可读性优先**:命名直白(见名知意),不炫技;三目只用于纯取值,复杂条件先提具名变量。 ## 5. 低侵入与派生一致性 - **低侵入**:新能力一律以插件 / 钩子 / 可选参数接入,不改核心签名、不动既有调用方;扩展字段必须可选,破坏性变更走新版本而非就地修改。 - **派生语义一致**:派生量只从上游单一来源推导,命名与上游字段对齐(如 `RowModel.total` 在整条管线中始终表示"筛选后、分页前的行数");禁止旁路重复计算同一派生量,保证"改一处、全局一致"。 - 派生链路顺序固定并写进注释(如 filter → sort → paginate),谁改变语义谁负责同步所有下游注释与文档。 ## 6. 架构取向 - **高可扩展是核心**:扩展点 = 插件 / 钩子 / 数据管线,而不是继承层级。 - **低复杂度、低抽象**:不为"将来可能"预先抽象;同一模式出现第二次再提取。 - **单文件尽量 < 200 行**:超出先拆职责,不拆"层"。 ## 7. 落地方式 - 新代码必须符合本规范;旧代码顺手迁移,不强制一次性全量重写。 - 后续可做成 `ua style` 检查项:导出缺注释、接口字段缺注释、类型散落实现文件、闭包状态未集中顶部。