
Effect v3 到 v4 如何适应 Equal.equals 默认结构相等变化并在需要时用 byReference【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effectEffect v3 升级到 v4 时Equal.equals的默认比较语义发生了改变v3 对普通对象和数组使用引用相等而 v4 默认改为结构相等。如果你的代码里有用Equal.equals比较对象/数组的地方或者依赖Equal.equivalence升级后行为会变化需要逐处确认只有个别对象仍必须按引用比较时才用 v4 新增的Equal.byReference/Equal.byReferenceUnsafe显式退回引用语义。本文基于仓库中的迁移文档 migration/equality.md 与源码 packages/effect/src/Equal.ts 给出完整的对照与验证方式。前提你正在把effect从 v3 升到 v4。MIGRATION.md 说明 Effect v4 目前处于 beta 阶段、API 可能在不同 beta 版本间变动v4 所有生态包共享同一个版本号例如使用effect4.0.0-beta.0时配套的effect/sql-pg也是effect/sql-pg4.0.0-beta.0本仓库当前packages/effect/package.json中的版本号为4.0.0-rc.115。effect/Equal模块在 v3 到 v4 的导入映射中保持不变见 migration/v3-to-v4.md 的 Import Mapeffect/Equal - effect/Equal所以导入路径不用改要改的是对比较行为的预期。v3 与 v4 的默认比较行为对照在 v3 中Equal.equals对普通对象和数组使用引用相等结构比较只能在structuralRegion内临时启用区域外两个内容相同的对象不相等引自 migration/equality.md// v3 import { Equal } from effect Equal.equals({ a: 1 }, { a: 1 }) // false — reference equality Equal.equals([1, 2], [1, 2]) // false — reference equality在 v4 中Equal.equals默认就是结构相等。普通对象、数组、Map、Set、Date、RegExp都按值比较不需要任何额外开启// v4 import { Equal } from effect Equal.equals({ a: 1 }, { a: 1 }) // true Equal.equals([1, [2, 3]], [1, [2, 3]]) // true Equal.equals(new Map([[a, 1]]), new Map([[a, 1]])) // true Equal.equals(new Set([1, 2]), new Set([1, 2])) // truev4 的源码中已经没有structuralRegion以上示例中的结果即为 v4 的默认行为可直接作为升级后的预期值。另外两点需要注意的行为变化实现了Equal接口的对象不受影响仍然走自定义相等逻辑与 v3 一致。NaN相等性变了v3 中Equal.equals(NaN, NaN)返回false遵循 IEEE 754v4 中NaN等于NaNEqual.equals(NaN, NaN) // v3: false, v4: truepackages/effect/src/Equal.ts 的文档进一步描述了 v4 结构比较的细节Date按 ISO 字符串比较RegExp按字符串表示比较数组逐元素比较Map和Set按条目比较且与顺序无关例如new Map([[a, 1], [b, 2]])与new Map([[b, 2], [a, 1]])相等普通对象递归比较可枚举键没有Equal实现的函数按引用比较。把Equal.equivalence改成Equal.asEquivalence把equals包装成Equivalence的函数在 v4 中更名了引自 migration/equality.md// v3 Equal.equivalencenumber() // v4 Equal.asEquivalencenumber()源码示例展示了 v4 的用法文档示例import { Array, Equal } from effect Array.dedupeWith([1, 2, 2, 3, 1], Equal.asEquivalencenumber()) // [1, 2, 3]升级时对全项目检索Equal.equivalence把命中的调用整体替换为Equal.asEquivalence即可asEquivalence在源码中标注since 4.0.0v3 中没有这个 API不存在向后兼容问题。需要引用相等时byReference与byReferenceUnsafe默认改成结构相等后如果你的某些对象必须保持同一引用才算相等的 v3 行为例如用对象身份做缓存键、监听器去重等v4 提供两个 opt-out引自 migration/equality.md 与 packages/effect/src/Equal.tsimport { Equal } from effect const obj Equal.byReference({ a: 1 }) Equal.equals(obj, { a: 1 }) // false — reference equality两者区别byReference(obj)— 返回一个使用引用相等的Proxy原对象不变。文档强调每次调用都会创建一个新的proxy所以byReference(x) ! byReference(x)属性读取会透传回原对象aRef.x仍是1。byReferenceUnsafe(obj)— 不创建 proxy直接把原对象自身标记为引用相等返回的就是原对象byReferenceUnsafe(x) x。文档说明它性能更好但标记对对象生命周期内是不可逆的会永久改变该对象的比较方式。源码文档给出的完整示例文档示例结果const a { x: 1 } const b { x: 1 } Equal.equals(a, b) // true const aRef Equal.byReference(a) Equal.equals(aRef, b) // false Equal.equals(aRef, aRef) // true aRef.x // 1以及byReferenceUnsafe的版本const obj1 { a: 1, b: 2 } const obj2 { a: 1, b: 2 } const marked Equal.byReferenceUnsafe(obj1) Equal.equals(obj1, obj2) // false Equal.equals(obj1, obj1) // true marked obj1 // true从实现看byReference内部就是byReferenceUnsafe(new Proxy(obj, {}))两者都通过一个内部WeakSet生效equals只要发现任一操作数在该集合里且两者不是同一引用就返回false。选择原则以文档措辞为准不想动原对象就用byReference接受永久标记以换取免 proxy 开销就用byReferenceUnsafe。验证升级后的行为升级完成后把下面这段 v4 行为检查粘到你的项目里跑一遍vitest或任何能执行 TS 的运行环境均可预期结果就是文档示例中的值import { Equal } from effect // 默认结构相等 console.log(Equal.equals({ a: 1 }, { a: 1 })) // 期望 true console.log(Equal.equals([1, [2, 3]], [1, [2, 3]])) // 期望 true console.log(Equal.equals(new Map([[a, 1]]), new Map([[a, 1]]))) // 期望 true console.log(Equal.equals(NaN, NaN)) // 期望 true // 引用相等 opt-out const ref Equal.byReference({ a: 1 }) console.log(Equal.equals(ref, { a: 1 })) // 期望 false console.log(Equal.equals(ref, ref)) // 期望 true如果上面任何一项与期望不符说明依赖的effect版本仍是 v3 或版本没有对齐v4 生态包要求同版本号见 MIGRATION.md。另外注意Equal.ts源码中的 doctest带import.meta.vitest标记的示例块本身就覆盖了这些断言可以参考 packages/effect/src/Equal.ts 中equals、byReference、byReferenceUnsafe的文档示例对照。限制与注意事项来自 packages/effect/src/Equal.tsequals文档的 Gotchas使用 v4 结构相等时要知道比较结果按对象对缓存在 WeakMap 中对象在第一次比较之后不应再被修改否则后续比较结果不可信。Map和Set的比较是 O(n²) 量级大集合上要注意开销。这两条是 v4 默认结构相等的固有代价v3 时代按引用比较时不存在这些问题。参考migration/equality.md — v3 到 v4 的相等性迁移说明本文主要依据migration/v3-to-v4.md — 完整的 v3 到 v4 导入映射与 API 差异MIGRATION.md — v3 到 v4 迁移总指南与版本约定packages/effect/src/Equal.ts —equals、byReference、byReferenceUnsafe、asEquivalence的源码与 doctest【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考