类型系统纪律(Type System Discipline)是一套在静态类型语言中设计和使用类型的指导原则,适用于设计类型、审查函数签名或编写代码的场景。其总体目标是让编译器拒绝不可能的状态、不匹配的基础类型和未处理的变体,并倾向于通过类型定义消除错误与特殊情况,而不是不断增加处理分支。
主要能力与原则:
-
让非法状态不可表示。用和类型(可辨识联合、带载荷枚举、密封类)建模变体,而不是用一堆可选字段组成一个允许矛盾组合通过编译的结构。例如 { completed: boolean; completedAt?: Date } 允许 completed: true 却没有日期;应改为从 completedAt 派生布尔值,或建模为 { kind: 'open' } | { kind: 'done'; at: Date }。如果能写注释解释某组字段何时有效,就应拆成和类型。
-
类型是构造,不是限制。从想要的值出发构建类型,而不是从更宽松的类型中用检查削出来。非空列表是头加尾,有效时间范围是起点加时长。选择无法构造非法值的形状,并在其上暴露调用者需要的接口。
-
为语义化基础类型打品牌。UserId 和 OrderId 底层都是字符串,但不应可互换。给每个类型独立身份,例如 TypeScript 中的品牌交叉类型或其他语言中的 newtype。在创建时验证一次,下游信任该类型。如果两个参数共享基础类型但含义不同,就为它们打品牌。
-
外部数据在解析前是无类型的。RPC 载荷、JSON、IPC 消息、CLI 参数、配置文件、环境变量、数据库行都属于此类。每个边界都要有解析函数,把非结构化输入转换为类型化模型。边界纪律原则技能说明了验证应放在哪里。
-
不要欺骗类型系统。强制转换、不安全强制和绕过编译器的断言函数是潜在的运行时崩溃。如果编译器无法证明某个事实,就去证明它(验证、收窄、精化模型),或者承认该转换是危险的。追踪每个 any、as 或 assertNotNull 到边界并在那里验证。
-
穷尽匹配是编译器的职责。对和类型的匹配在新增变体而未处理时必须编译失败,这样编译器会告诉下一个代理在哪里添加分支。使用语言的惯用法:TypeScript 中的 never 类型绑定、Rust 中未标注的 match、Haskell 中的 -Wincomplete-patterns、Kotlin 中密封类匹配的穷尽性。
-
从权威模式派生类型。当 protocol buffer、OpenAPI 规范、GraphQL 模式、数据库迁移、设计令牌文件或其他文件拥有某个形状时,应从它派生,而不是手工编写并行类型。参见 encode-lessons-in-structure 原则技能。
-
仅在出现部分性时强化类型。运行时断言、空值检查或“这不应发生”的抛出,标记了类型过弱的位置。把该检查上推到类型中,然后停止。类型系统的职责是跟踪每个使用点必须处理的情况,而不是尽可能精确地描述数据。优先使用全函数:空列表的 sum 是 0,所以接受普通列表;空列表的 head 没有答案,所以要求非空列表。如果否则不会 panic,就保留普通类型。
使用方式:该技能以原则形式提供,在编写或审查静态类型代码时参照执行。对于 TypeScript 语法,可参考 typescript-best-practices 技能。
适用场景:设计类型、审查函数签名、编写任何静态类型语言代码。
限制:资料未提供具体安装命令、平台支持、收费信息或效果数据。