在 #5181(IDataDriver 的 query 参数去掉冗余 object)落地过程中顺带实测出来的,与该单的修复无关,也不由该单的修复解决。单独记录,免得 cloud 车道按 #5181/#4860 的证据行去期待一个不会发生的效果。
实测
packages/spec/src/data/filter.zod.ts 的 TS 类型 FilterCondition 是一个开放索引签名:
export type FilterCondition = {
[key: string]:
| any // 隐式相等 key: value
| z.infer< typeof FieldOperatorsSchema > // 显式算子 key: { $op: value }
| FilterCondition; // 嵌套关系
} & { $and?: …; $or?: …; $not?: … };
索引签名的值类型里有 any,所以任何键、任何值都合法。实测(packages/spec/src/contracts/data-driver.test.ts,#5181 的 PR 里作为一条诚实性断言留下):
// 没有任何 cast,tsc 全绿
const unknownOperator: DriverQuery = { where: { name: { $like: 'acme%' } } };
pnpm --filter @objectstack/spec typecheck 对这一行零报错。
为什么值得记一笔
#5181 正文(转录自已关闭的 #4860)写着「cloud#1030 的 $like 本可在类型层拦住」。这一句不成立:cloud 侧那片 as any 确实关掉了一批类型检查(orderBy 的 SortNode、fields、limit、$and/$or/$not 的结构),但没有关掉「where 里的未知 $ 算子」这一条 —— 因为它从来就没被打开过。#5181 删掉 cast 之后,$like 依然编译通过,依然只在运行时被校验层拒收。
这不是要推翻 #5181 的判断(它按「删掉冗余参数」自身的理由是成立的,且实测确实恢复了 orderBy/fields/limit 那几条),只是把它的作用面说准。
#5701(已 closed/completed)走的是校验期词表:zod 层移除 $regex、新增 $icontains、未知算子响亮拒收。那条路线管的是运行时的门,结构上管不到 TS 类型这道门 —— FilterCondition 是手写 TS 类型,不是从 zod 推导出来的,两者各走各的。所以本单不是 #5701 的子项,也不 blocked-by 它。
权衡(不预设结论,留给分诊)
想把类型这道门也关上,就得让 FilterCondition 的索引签名从 any 收窄成「字段名 → 值 | 封闭算子对象」的联合。代价是真实的,且不小:
判据不明显,因此按 finding 记录、不挂 pm:queue,请分诊轮定级。
会话:session_011M7UwH25Unfi73UHim7ajY(#5181 实施期间发现,未认领)
在 #5181(
IDataDriver的 query 参数去掉冗余object)落地过程中顺带实测出来的,与该单的修复无关,也不由该单的修复解决。单独记录,免得 cloud 车道按 #5181/#4860 的证据行去期待一个不会发生的效果。实测
packages/spec/src/data/filter.zod.ts的 TS 类型FilterCondition是一个开放索引签名:索引签名的值类型里有
any,所以任何键、任何值都合法。实测(packages/spec/src/contracts/data-driver.test.ts,#5181 的 PR 里作为一条诚实性断言留下):pnpm --filter @objectstack/spec typecheck对这一行零报错。为什么值得记一笔
#5181 正文(转录自已关闭的 #4860)写着「cloud#1030 的
$like本可在类型层拦住」。这一句不成立:cloud 侧那片as any确实关掉了一批类型检查(orderBy的SortNode、fields、limit、$and/$or/$not的结构),但没有关掉「where里的未知$算子」这一条 —— 因为它从来就没被打开过。#5181 删掉 cast 之后,$like依然编译通过,依然只在运行时被校验层拒收。这不是要推翻 #5181 的判断(它按「删掉冗余参数」自身的理由是成立的,且实测确实恢复了
orderBy/fields/limit那几条),只是把它的作用面说准。与 #5701 / #4706 的关系
#5701(已 closed/completed)走的是校验期词表:zod 层移除
$regex、新增$icontains、未知算子响亮拒收。那条路线管的是运行时的门,结构上管不到 TS 类型这道门 ——FilterCondition是手写 TS 类型,不是从 zod 推导出来的,两者各走各的。所以本单不是 #5701 的子项,也不 blocked-by 它。权衡(不预设结论,留给分诊)
想把类型这道门也关上,就得让
FilterCondition的索引签名从any收窄成「字段名 → 值 | 封闭算子对象」的联合。代价是真实的,且不小:string,所以「未知$op」和「某个恰好以$开头的字段名」在类型层不可区分,除非按前缀做模板字面量类型(`$${string}`单独一支);where的地方,迁移面远大于 [spec] IDataDriver 的 query 参数要求QueryAST.object与第一实参重复 —— 下游被迫as any(20 处实测),提议 Omit/optional 化 #5181 的 6 处;判据不明显,因此按 finding 记录、不挂
pm:queue,请分诊轮定级。会话:
session_011M7UwH25Unfi73UHim7ajY(#5181 实施期间发现,未认领)