关于 principle-type-system-discipline
面向开发者的跨语言类型系统技能,旨在让编译器拒绝不可能状态、混用的基本类型和未处理的变体,并强调构造式建模、边界解析及穷尽检查。
主要功能
- 01让非法状态无法表示
- 02从有效值构造类型
- 03为语义基本类型添加品牌
- 04在边界解析无类型数据
- 05要求穷尽匹配
- 06从权威 Schema 派生类型
适用场景
- 01设计不含矛盾字段的变体
- 02区分含义不同的 ID
- 03验证进入应用的数据
- 04确保新增变体触发编译期处理
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mdsmithaustin/ pstack --skill principle-type-system-discipline安装后在 Claude Code 中输入/principle-type-system-discipline确认已加载。
附带文件agents/openai.yaml
详细介绍
类型系统纪律
让编译器拒绝不可能的状态、不匹配的基本类型和未处理的变体。与其不断增加处理程序,不如优先从定义上消除错误和特殊情况。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 参数、配置文件、环境变量、数据库行。应在每个边界设置解析函数,将非结构化输入转换为类型化模型。principle-boundary-discipline 技能说明了验证应放在哪里。
- 不要欺骗类型系统。 类型转换、不安全强制转换,以及绕过编译器的断言函数,都是潜在的运行时崩溃。如果编译器无法证明某个事实,就证明它(验证、缩小范围、细化模型),否则就承认类型转换是一种风险。追踪每个
any、as或assertNotNull,直到其所在边界,并在那里验证。 - 穷尽匹配是编译器的工作。 对和类型的匹配必须在新增变体却未处理时编译失败,这样编译器就能告诉下一个 Agent 应在哪里添加分支。使用你所用语言的惯用方式:TypeScript 中使用类型为
never的绑定,Rust 中使用未注释的match,Haskell 中使用-Wincomplete-patterns,Kotlin 中使用密封类匹配穷尽性检查。 - 根据权威模式派生类型。 如果 Protocol Buffer、OpenAPI 规范、GraphQL 模式、数据库迁移、设计令牌文件或其他文件定义了某种结构,就从中派生类型,而不是手动编写一套并行类型。使用 Skill 工具调用
principle-encode-lessons-in-structure。 - 只在存在部分性时增强类型。 运行时断言、空值检查或“这不应该发生”的抛错,都表明类型过于宽泛。将该检查上移到类型中,然后就此为止。类型系统的职责是追踪每个使用位置必须处理的情况,而不是尽可能精确地描述数据。优先使用全函数。空列表的
sum为 0,因此它接受普通列表。空列表的head没有答案,因此它要求非空列表。如果不做任何修改也不会发生崩溃,就保留普通类型。
评论
支持 Markdown