paleo-typescript-style 是 paleo/paleo-skills 技能集合中的一项 TypeScript/JavaScript 编码风格约定。其用途是在编写或审查 TypeScript/JavaScript 代码之前阅读,包括规格(spec)或计划(plan)中出现的代码。\n\n通用规则:不应保留无用(死)代码(YAGNI 原则);不要写多个连续空行;修改 linter 规则必须先讨论再实施;代码中不应包含被注释掉的代码,除非有注释说明原因。\n\n代码组织:使用在前、实现在后;例外是继承场景——接口扩展另一接口时先写父接口。代码自上而下排列,每个文件如同一段故事,从入口点读到叶子。顺序为:导入;模块级常量与变量(先导出的后内部的);共享类型(主类型在前,其引用的类型在后);入口(导出)函数;入口调用的内部函数,按调用顺序排列。模块级常量与变量必须紧跟导入之后、任何类型定义/函数/类之前。函数先写调用者再写被调用者,辅助函数紧贴其调用者下方;被多个兄弟函数调用的辅助函数放在第一个调用者之后。类型同样先写主类型再写其引用类型;仅用于单个函数/类签名的类型须紧贴该声明之前。导出本身不是排序标准。\n\n代码质量:力求优雅;避免冗余操作(尤其图片转换等昂贵操作);避免重复代码与逻辑;把已算出的值传给函数而非重算;尽可能用早返回简化流程;离开当前流程的语句(throw、return、continue、break)能一行写完就一行写完;用清晰命名减少注释;函数保持小且单一职责;避免 any,找不到合适类型时在 any 后加 /* FIXME */;默认不导出,仅导出被外部导入的函数/变量/类;导出函数签名中使用的接口也必须导出。\n\n导入:始终使用 ESM 语法,避免模块间循环导入。\n\nTypeScript/JavaScript 偏好:禁用 enum 和 namespace;优先 const 而非 let;优先 undefined 而非 null;优先 ?? 而非 ||;优先 ++i/--i;优先 new Error();顶层优先 function/class 声明式语法;顶层函数、类、接口之间保留空行;getter/setter 实现不得抛异常;优先 interface 而非 type 别名;泛型参数用单个大写字母;不区分缺失属性与值为 undefined 的属性;联合类型字符串字面量用 camelCase;不用空字符串作默认值除非确实需要;字符串、数字、布尔值的存否不得通过布尔强制转换测试,对象和数组可以;不要在默认值时显式赋值或返回 undefined;避免 as any 或类型断言,确需时用内联注释说明;除包索引文件外不重新导出;避免内联 import(...) 类型和 await import()。\n\nOOP:优先工厂函数而非类;优先带上下文对象的函数而非类;避免类继承,除非框架要求。\n\n添加依赖:先搜索代码库复用现有版本,找不到再用默认安装命令安装最新版。\n\n改进代码质量:代码没问题就直说,否则按 SRP、DRY、YAGNI 原则保持代码整洁可维护高效。SRP 可视为叙事分解——调用者像一段点明发生什么的段落,每个辅助函数展开其中一句;始终在调用者之后写子函数;不导出外部未使用的函数;函数实现尽量不超过一屏(约 50 行);保持代码自解释而非加解释性注释。DRY:见到重复逻辑就重构成可复用函数。YAGNI:不保留未使用的变量、函数、实现等。警示信号:回退到空字符串或零很少有正当理由,需检查每个 ?? "" 和 ?? 0;类型断言常是误解类型;避免 any;不要用 ReturnType<T>、Parameters<T> 或 SomeType["someMemberName"] 而应导入实际类型。\n\n注释:越少越好;删除与代码冗余的注释(如 // Create a new task 紧跟 createANewTask());只保留记录 hack、TODO、异常情况或目的不明显的注释;不把注释当作当前任务的说明;JSDoc 仅在增加有意义信息时使用。\n\n适用场景为团队或个人在 TypeScript/JavaScript 项目中统一编码风格、代码审查与重构时参考。限制:该资料为风格约定,未提供工具安装、IDE 集成、自动检查配置或收费信息,暂未提供。
paleo-typescript-style
编程与开发
更新于 11-06 16:18