资讯动态

Effect 库新增 `Effect.transposeOption`:在 `Option` 与 `Effect` 之间优雅地交换容器层级

发布时间:2026/9/15 12:53:17 来源:尧图企业网站定制
Effect 库新增Effect.transposeOption在Option与Effect之间优雅地交换容器层级【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect导读本文围绕仓库变更记录 .changeset/pre/eff-849-transpose-option.md 引入的Effect.transposeOption组合子展开讲解它如何将OptionEffectA, E, R转置为EffectOptionA, E, R从而在可选值存在时才运行副作用、缺失时直接成功返回None的场景中消除层层嵌套。读完本文你将掌握该 API 的精确签名、底层实现原理、三个方向的类型行为以及它在真实业务如异步等待可选完成信号中的典型用法。一、变更背景这是 effect 4.0 RC 阶段的一次 patch 级新增该变更记录位于仓库的预发布变更集目录.changeset/pre/下文件头部声明--- effect: patch ---它表明本次改动作用于核心包effect级别为patch补丁级纯新增 API不破坏既有行为。同时仓库根目录的 .changeset/pre.json 显示当前处于pre预发布模式、tag为rcpackages/effect/package.json 中记录的版本为4.0.0-rc.115。也就是说该功能是在 effect 4.0 发布候选阶段合入的增量能力。变更记录的正文只有一句话AddEffect.transposeOptionfor converting anOptionEffectA, E, Rinto anEffectOptionA, E, R.虽然记录本身极简但该 API 已在源码中完整落地公开导出、JSDoc、内部实现与测试用例一应俱全足以支撑一篇完整的实战解析。二、问题域为什么需要转置transpose在 effect 的类型体系中Option表示可有可无的成功值EffectA, E, R表示一个可能成功产出A、可能失败产出E、并可能依赖环境R的运算。当二者嵌套时会出现两种情况EffectOptionA, E, R副作用必然执行执行后产出可能缺失的值OptionEffectA, E, R副作用是否执行取决于可选值是否存在。transposeOption处理的是第二种形态。它的存在价值在于只有当可选值确实存在时才运行其内部的 Effect而当可选值为空时不运行任何副作用直接得到一个成功的None。这正是转置一词的含义——把两个容器的内外层级互换OptionEffectA, E, R ──转置──▶ EffectOptionA, E, R 外层可选、内层效应 外层效应、内层可选从源码结构看effect 内部还有其他转置变体例如 Result.transposeOption 处理OptionResultA, EEffect.transposeOption是这一族组合子在 Effect 容器上的对应实现。三、API 签名与语义公开 API 定义在 packages/effect/src/Effect.ts归属category converting转换类标注since 3.13.0export const transposeOption: A never, E never, R never( self: OptionEffectA, E, R ) EffectOptionA, E, R internal.transposeOption其完整 JSDocpackages/effect/src/Effect.ts明确给出了三条核心语义输入输出说明None成功产出None的 Effect不执行任何副作用直接成功Some(effect)且内部成功EffectSome(A)运行内层 Effect将其成功值包进SomeSome(effect)且内部失败失败内层失败原样透传错误类型E不变类型层面看A、E、R三个类型参数完全透传错误通道E和环境需求R都不会因转置而改变或放宽内层 Effect 的失败语义被完整保留。四、底层实现一行代码背后的两个辅助函数真正的实现位于内部模块 packages/effect/src/internal/effect.ts/** internal */ export const transposeOption A never, E never, R never( self: Option.OptionEffect.EffectA, E, R ): Effect.EffectOption.OptionA, E, R Option.isNone(self) ? succeedNone : map(self.value, Option.some)整个实现是一个三目表达式逻辑非常直接用Option.isNone(self)判断外层是否为None若是None返回succeedNone——即Effect.succeed(Option.none())一个立即成功、产出None的 Effect否则取出Some中包裹的 Effectself.value通过map(self.value, Option.some)在其成功后把结果包进Some。实现所依赖的两个辅助函数也定义在同一文件内packages/effect/src/internal/effect.ts/** internal */ export const succeedSome A(a: A): Effect.EffectOption.OptionA succeed(Option.some(a)) /** internal */ export const succeedNone: Effect.EffectOption.Optionnever succeed( Option.none() )值得注意的是由于内层 Effect 只有在Some分支才会被map引用None分支根本不会触碰内层 Effect因此空值时副作用天然不会执行——这不是运行时的惰性优化而是纯函数组合的直接结果。也正因如此返回类型中A在None路径下退化为neversucceedNone的类型为EffectOptionnever类型系统能正确表示空值时不可能有值产出这一事实。五、完整使用示例来自 JSDoc 的 doctest公开 API 的 JSDoc 附带了一个可直接运行的 doctest 示例packages/effect/src/Effect.ts展示了最基本、也是最有代表性的用法——把Option.some(Effect.succeed(42))转置成可运行的programimport { Effect, Option } from effect const some Option.some(Effect.succeed(42)) // ┌─── EffectOptionnumber, never, never // ▼ const program Effect.transposeOption(some) Effect.runSync(program) // Option.some(42)在这个例子中some的类型是OptionEffectnumber, never, never经transposeOption后变为EffectOptionnumber, never, never。由于program的失败通道是never、环境需求是never可以直接用Effect.runSync同步执行并得到Option.some(42)。六、测试验证三条路径逐一覆盖仓库的测试套件对transposeOption的三种行为都有明确断言位于 packages/effect/test/Effect.test.tsdescribe(transposeOption, () { it.effect(transposes a none, () Effect.gen(function*() { const result yield* Effect.transposeOption(Option.none()) assert.deepStrictEqual(result, Option.none()) })) it.effect(transposes a some containing a success, () Effect.gen(function*() { const result yield* Effect.transposeOption(Option.some(Effect.succeed(A))) assert.deepStrictEqual(result, Option.some(A)) })) it.effect(transposes a some containing a failure, () Effect.gen(function*() { const error yield* Effect.transposeOption(Option.some(Effect.fail(error))).pipe(Effect.flip) assert.strictEqual(error, error) })) })三个用例分别对应上一节的三种语义None路径Effect.transposeOption(Option.none())产出Option.none()且全程不执行任何 Effect成功路径Option.some(Effect.succeed(A))转置后产出Option.some(A)内层成功值被正确包裹失败路径Option.some(Effect.fail(error))转置后错误通过Effect.flip取出断言为字符串error——证明内层失败被原样透传不会被吞掉或改写。七、实战场景等待可选的异步完成信号transposeOption最有价值的应用场景之一出现在 packages/effect/src/Deferred.ts 的 JSDoc 示例中——当手头持有的是一个可选的 Deferred异步完成信号并希望信号存在就等待它完成不存在就直接继续时const afterValue yield* Effect.transposeOption(afterCompletion)这里afterCompletion的类型是OptionDeferred...之类的可选句柄具体形态取决于上下文。在引入transposeOption之前这种可选等待需要手写Option.match或嵌套的flatMap分支现在只需一次转置代码即变为一条线性链条Effect.gen(function*() { const afterValue yield* Effect.transposeOption(afterCompletion) // EffectOptionA, E, R // afterValue: OptionA —— 有信号则等到其完成值无信号则为 None })这种模式同样适用于更泛化的条件执行场景按配置可选执行的副作用例如日志开关开启才上报指标Option.some(reportEffect)转置后统一得到EffectOption...无需在调用处散落if分支多路可选项的线性组合配合Effect.all、flatMap使用把多个可选 Effect统一成同一个错误通道E与同一环境R便于组合与重试调度。八、与周边 API 的关系transposeOption不是孤立的组合子它处于 effect 的一族可选值处理工具之中Option 模块Option本身提供了transpose把ArrayOptionA或类似容器转置Effect.transposeOption是 Effect 这一容器与Option组合时的专门版本Result.transposeOption处理OptionResultA, E→ResultOptionA, E语义与Effect版完全同构None变Success(None)、Some(Failure(e))变Failure(e)标注since 3.14.0同属transposing范畴其 JSDoc 还通过see transposeMapOption提示可以映射 转置一步完成Effect.fromOption方向恰好相反——把OptionA转换成有值成功、空值失败默认NoSuchElementError的 Effect。fromOption强调空值即失败而transposeOption强调空值即成功二者共同覆盖了可选值在 Effect 世界里的两种处理哲学可依据业务语义选用。API输入输出空值语义Effect.transposeOptionOptionEffectA, E, REffectOptionA, E, R空值 → 成功NoneEffect.fromOptionOptionAEffectA, NoSuchElementError空值 → 失败Result.transposeOptionOptionResultA, EResultOptionA, E空值 →Success(None)九、小结Effect.transposeOption是 effect 在 4.0 RC4.0.0-rc.115阶段通过 .changeset/pre/eff-849-transpose-option.md 引入的一个小而美的组合子签名OptionEffectA, E, R→EffectOptionA, E, R错误通道与环境需求完全透传语义None直接成功为None且不执行副作用Some(effect)运行内层 Effect 并包裹成功值内层失败原样透传实现internal/effect.ts 中一行三目表达式借助succeedNone/map完成验证Effect.test.ts 对三种路径均有断言场景适用于可选值时才有副作用、缺失时直接成功的条件执行与可选异步等待如 Deferred.ts 所示。当你在代码中遇到是否执行某个 Effect 取决于一个可选值的胶水逻辑时Effect.transposeOption就是把这个两层嵌套压平成一条线性 Effect 链的标准答案。【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价