有些虫子用堆积的痕迹宣布自己.
其他人只是让你的代码 安静地停止任何意义。
这大约是第二种——一种TypeScript monorepo中的依赖性解析问题,它没有投出,没有明显地辜负CI,并且把真正的挖掘到根上,因为症状看起来跟原因完全不一样.
使用 npm 工作空间的症状 We're a Next.js + TypeScript monrepo,位于Supabase/Postgres上方有行级安全政策.
一个下午,一名队友打开了公关, 类型检查器标出什么 看起来像一个无关的函数 是一个类型的参数。
没有,没有。
这就是类型TypeScript用来表示"这个代码路径是无法到达的"或"没有价值可以满足这个类型".
有关职能非常可以实现。
在生产中,它一直被称作成功。
TypeScript对此完全错误——或者说TypeScript被正确地告诉了错误的事情.
为什么最糟糕的症状是类型系统中的黑洞.
一旦一个类型崩溃, 下游所有触碰它的东西 也往往变得不可忍受 或不敏感, 因为没有价值可以居住。
这意味着第一个看到出错的地方是很少靠近实际原因的地方——在检查者别无选择只能抱怨的时候,该类型已经对几个hop错误了.
这个地产使这类虫子真正地危险地被直觉调试.
盯着标注的函数几乎什么也没有告诉你,因为函数是无辜的.
你必须反向工作 通过类型的来源 而不是从症状向前。
追踪回来 调查大致是这样的:确认这不是逻辑错误.
运行时的行为是正确的。
这排除了我们自身职能机构的任何内容,并具体指向类型层——无论是我们的类型定义,还是其中的上游定义。
分解类型,而不是代码。
我通过每种中间型别名和一般约束 追溯了违法类型 直到我发现它不再正常的地层 它来自我们内部一个工作空间套件的再出口型号。
看看有什么变化 锁上的文件,不是来源,是这里的移动——来源没有改变.
过渡性依赖性撞出一个小版本,在熔炉下应该是安全的。
在隔离中复制。
我将每个工作空间包固定在从出错前的准确版本上,确认类型错误消失,然后一次碰上一个依赖,直到再次出现.
这隔离了确切的包和版本.
了解实际机制.
新的小版本改变了内部条件类型,在价值水平上是倒向相容的,但在我们所依赖的某种具体通用使用模式上则不是推论相容的。
Semver保护你不被打破运行时的行为;它没有说打破类型推论用于边缘案例的通用.
这才是真正的教训 固定,和更重要的固定 即时固定是一个版本针 有一条评论 解释确切的原因, 连接到孤立的 repro。
这虽然必要,但还不够——一个没有解释的针头只是成为了下一个人物的谜团,最终有人"清理了它"并重新引入了虫子.
更为重要的是将其写出:症状是什么样子的,为什么它具有误导性,发现它的分节方法,以及基础机制(在过渡性依赖性中的类型层面的侵权).
那医生就是在下次队友打出类似东西时 将3小时的调试会话变成5分钟的固定会话 当一个类型错误 涉及无辜的代码 可疑的出处 不是逻辑 而它的堂兄弟通常是上游问题的下游症状.
将依赖图分为两部分,而不仅仅是你自己的承诺。
运行时间正确, 类型断裂的更改对正常“ Did my code