mcpField
P
principle-type-system-discipline

principle-type-system-discipline

github.com/q-qp-p开发146 次安装2 周前更新
代码仓库

关于 principle-type-system-discipline

面向开发者的类型系统实践技能,帮助构建更安全的类型模型。它强调直接表达有效状态、在边界解析数据,并借助编译器发现遗漏分支。

主要功能

  1. 01让非法状态无法通过类型表达
  2. 02从有效值构造类型
  3. 03为语义不同的原始值添加品牌类型
  4. 04在边界解析外部数据
  5. 05穷尽检查所有变体
  6. 06从权威模式派生类型

适用场景

  1. 01建模互斥状态
  2. 02避免不同 ID 类型混用
  3. 03验证 JSON 等外部输入
  4. 04变更后发现未处理的变体

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/q-qp-p/pstack --skill principle-type-system-discipline

安装后在 Claude Code 中输入/principle-type-system-discipline确认已加载。

详细介绍

类型系统纪律

让编译器拒绝不可能的状态、不匹配的基本类型和未处理的变体。与其不断增加处理逻辑,不如从定义上消除错误和特殊情况。TypeScript 语法请参阅 typescript-best-practices 技能。

  • 让非法状态无法表示。 将变体建模为和类型(判别联合、带载荷的枚举、密封类),而不是一组可选字段,因为相互矛盾的组合也能通过编译。{ completed: boolean; completedAt?: Date } 允许 completed: true 却没有日期。可以从 completedAt 推导布尔值,或建模为 { kind: 'open' } | { kind: 'done'; at: Date }。如果你需要写注释来说明字段组合在什么情况下有效,就应该将其拆分为和类型。
  • 类型是构造,不是限制。 从你想要的值出发构造类型,而不是先采用宽松类型,再通过检查剔除不需要的值。非空列表由一个头元素和其余元素组成。有效时间范围由开始时间和持续时长组成。选择无法构造非法值的形状,并在其上公开调用方需要的接口。
  • 为有语义的基本类型添加品牌。 UserId 和 OrderId 底层都是字符串,但不应互换。为它们分别定义类型,例如在 TypeScript 中使用品牌交叉类型,或在其他语言中使用 newtype。在创建时验证一次,下游代码就可以信任其类型。如果两个参数的基本类型相同,但含义不同,就为它们添加品牌。
  • 外部数据在解析前都没有类型。 RPC 载荷、JSON、IPC 消息、CLI 参数、配置文件、环境变量、数据库行,都属于此类。每个边界都应有一个解析函数,将非结构化输入转换为带类型的模型。boundary-discipline 原则技能说明了验证应放在哪里。
  • 不要欺骗类型系统。 绕过编译器的类型转换、不安全强制转换和断言函数,都会埋下运行时崩溃的隐患。如果编译器无法证明某个事实,就应该证明它(通过验证、收窄类型或完善模型),否则就要承认类型转换存在风险。沿着每个 any、as 或 assertNotNull 追溯到边界,并在那里进行验证。
  • 穷尽匹配是编译器的职责。 对和类型进行匹配时,如果新增变体却未处理,就必须编译失败,让编译器告诉下一个 Agent 应在哪里添加分支。使用语言惯用的方式:TypeScript 中绑定到 never 类型的变量、Rust 中未标注类型的 match、Haskell 中的 -Wincomplete-patterns,或 Kotlin 中对密封类的穷尽匹配检查。
  • 从权威架构定义派生类型。 如果协议缓冲区、OpenAPI 规范、GraphQL 架构、数据库迁移、设计令牌文件或其他文件定义了某种结构,就应从中派生类型,而不是手动创建一套平行类型。请参阅 encode-lessons-in-structure 原则技能。
  • 只在出现不完整性的地方强化类型。 运行时断言、空值检查或“这种情况绝不应该发生”的抛错,都表明类型过于宽松。将检查提升到类型中,然后就此为止。类型系统的职责是追踪每个使用点必须处理的情况,而不是尽可能精确地描述数据。优先使用全函数。空列表的 sum 结果是 0,因此它接受普通列表。空列表的 head 没有答案,因此它要求非空列表。如果没有其他情况会导致程序崩溃,就保留普通类型。

评论

支持 Markdown