news 2026/10/7 15:06:16

pstack原则09类型系统纪律:如何让非法状态不可表示

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pstack原则09类型系统纪律:如何让非法状态不可表示

pstack原则09类型系统纪律:如何让非法状态不可表示

【免费下载链接】pstack-claudeClaude Code, Codex, Copilot, Pi, OpenCode, Gemini, and Prime Agent versions of Poteto's pstack. Rigorous agent workflows with Cursor primitives translated for other harnesses.项目地址: https://gitcode.com/GitHub_Trending/ps/pstack-claude

pstack 类型系统纪律是 pstack 原则系列的第 09 条:把类型检查器当作"证明助手",在编译期就消灭非法状态。读完本文,你会掌握判别联合、品牌类型、边界解析等 8 个实操模式,学会让非法状态不可表示——从源头减少运行时错误,而不是出错后再打补丁。

为什么需要"类型系统纪律"?

类型检查器不只是报错工具,它是一位证明助手(proof assistant)。核心思想一句话:

类型系统让你忽略掉的每一种情况,都会变成编译器本可以阻止的运行时崩溃。

比起到处添加防御性检查,更好的做法是:把错误和特例直接定义到不存在。这条原则适用于任何静态类型语言(TypeScript、Rust、Kotlin、Swift……),在 pstack 仓库中写作技能文件 principle-type-system-discipline/SKILL.md。

判别联合:让矛盾状态根本写不出来

新手最容易掉进"可选字段袋"陷阱:

// 坏味道:completed 为 true 却没有时间,编译器却不报错 type Task = { completed: boolean; completedAt?: Date };

这个定义允许"已完成但没有完成时间"这种无意义的状态。用判别联合(discriminated union)重写即可:

// 好:每个合法状态都是独立分支,非法组合无法构造 type Task = { kind: 'open' } | { kind: 'done'; at: Date };

每个变体用kind字面量区分,"已完成但没有时间"从此无法被写出。这就是"让非法状态不可表示"的精髓。

类型是"构造"出来的,不是"限制"出来的

别拿运行时检查去雕刻一个宽松类型,而是从合法值出发把类型搭起来:

  • 非空列表 = 首元素 + 其余元素,而不是"列表 + 到处检查长度"
  • 有效时间区间 = 开始时间 + 时长,而不是两个必须手动保序的时间戳

原文有个很妙的判据:当某个 bug 让你问出"等等,这种组合真的可能发生吗?"时,说明类型太松了。

品牌类型:UserId 和 OrderId 不能互换

UserId和OrderId底层都是字符串,但绝不该互换。用品牌类型(branded types,TypeScript 中通常是& { readonly __brand: "UserId" }这样的交叉类型)让编译器拦住参数传错。

记住八个字:创建时验证一次,下游信任类型。

边界验证:外部数据解析前都是"无类型"

RPC 响应、JSON、命令行参数、环境变量、数据库行……外部数据在解析之前都是"无类型"的。正确姿势是在每个边界放置解析函数,把无结构输入转成类型化模型;跨过边界后就信任内部类型,不要在调用链深处重复验证。

TypeScript 里这意味外部输入应标为unknown而不是any——前者逼你收窄,后者只是闭眼。

不要对类型系统撒谎

as断言、!非空断言、绕过编译器的断言函数,都是潜伏的运行时崩溃。如果编译器无法证明某个事实,就亲自证明它(验证、收窄、细化模型);证明不了,就承认这个断言是风险点。

穷举检查交给编译器

对联合类型做匹配时,让编译器保证"新增变体但没人处理 → 编译失败"。TypeScript 的惯用法是在switch的default分支写const _exhaustive: never = x;。这样下个月有人加变体时,编译器会明确告诉下一个人(或下一个 AI Agent)该在哪里补 case。

从权威 Schema 派生类型

如果 protobuf、OpenAPI 或数据库迁移文件已经定义了某种形状,从它派生类型,而不是手写一个平行接口。重复的形状必然随 schema 演进而漂移。

克制:只在出现"部分性"时才强化类型

类型系统的职责是跟踪每个调用点必须处理哪些情况,而不是把数据描述得越精确越好:

  • 空列表求和是 0 → 普通T[]就够
  • 空列表取首元素无解 → 输入必须是"非空版本"

优先全函数(total functions)。当某处出现运行时断言、空值检查或"这里绝不应该发生"的 throw,就标记出类型太弱的地方——把检查上提到类型里,然后停手。

代码评审时的 6 问自检清单 📋

原文附带 6 个自检问题,可直接用于 review:

  1. 你能否写一条注释解释"这种字段组合何时合法"?能 → 类型太松,拆成联合。
  2. 两个函数参数同为原始类型、含义却不同?→ 加品牌。
  3. 那个any、as是从哪来的?→ 追到边界去验证。
  4. 新增变体时,编译器会告诉下一个人去哪补 case 吗?→ 不会就补穷举检查。
  5. 这个类型是不是复制了别的文件拥有的形状?→ 改为派生。
  6. 我强化类型是为了让操作变全,还是单纯想更精确?→ 后者就保持简单类型。

在 pstack 中如何自动应用这些原则 🤖

pstack 是把 Poteto 的 pstack 移植到 Claude Code、Codex、Pi 等运行时的技能栈(skill stack)。这些原则不需要你手动背诵——typescript-best-practices技能在读写.ts文件时会自动加载,并优先应用类型系统纪律。相关路径:

资料路径
原则原文(8 个模式 + 6 问自检)principle-type-system-discipline/SKILL.md
TypeScript 规则速查表typescript-best-practices/SKILL.md
每条规则配套示例references/patterns.md
原则总索引(架构组)poteto-mode/SKILL.md

想体验完整工作流,直接对 Agent 说一句话即可,例如:"Use poteto-mode to fix the search filter resetting when I change pages",它会自动选剧本、委派执行并给出失败与通过的证据。

小结

一句话记住原则 09:类型系统不是 lint 工具,是你的第一道运行时。把非法状态定义到不存在、给语义值打品牌、在边界解析外部数据、不对编译器撒谎、穷举交给编译器——绝大多数"不可能"的运行时崩溃,会在编译期就消失。

【免费下载链接】pstack-claudeClaude Code, Codex, Copilot, Pi, OpenCode, Gemini, and Prime Agent versions of Poteto's pstack. Rigorous agent workflows with Cursor primitives translated for other harnesses.项目地址: https://gitcode.com/GitHub_Trending/ps/pstack-claude

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 15:06:15

HarmonyOS 7 ImageAnimator:长动图帧时序修正与前后台恢复

一、那张“偶尔加速”的动图没有坏 FramePulseLab 原本只是一个动效素材验收页:设计同学把 metro_signals.gif 放进 resources/rawfile,开发侧显示帧数、原始时长和当前生命周期,确认无误后再把素材交给业务页面。文件是 720720、48 帧&#…

作者头像 李华
网站建设 2026/10/7 15:05:35

UR3与Realsense L515手眼标定实战:从AX=XB到抓取精度校准

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 15:05:22

Linux 内存回收机制:水位线、kswapd 与 Direct Reclaim

Linux 内存回收机制:水位线、kswapd 与 Direct Reclaim源码基线:Linux v6.18.9(mm/page_alloc.c / mm/vmscan.c)。 现象:内存明明还有(free 数 GB),进程却偶发卡顿几百毫秒&#xff…

作者头像 李华
网站建设 2026/10/7 15:05:08

AI 练习项目 智能数仓问答

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 15:05:01

云数据中心特点

云数据中心特点:资源池化。通过虚拟化技术将计算,存储和网络资源统一整合,形成共享资源池,提高资源利用率。按需服务,根据业务需求动态分配和回收资源,实现资源的弹性供给。高可靠性,采用冗余设…

作者头像 李华