在fp-ts中是否存在Do/Bind模式用于创建多类型对象?
解决方案:实现极简同步版
Do/bind工具 你的核心需求是无额外包装的同步链式对象构建,不需要引入IO/Option/Either这些带额外语义的Monad,完全可以自己实现一套极简的Do和bind函数,完美匹配你想要的写法:
1. 实现核心工具函数
// 辅助类型:跟踪已绑定的键值对 type Bindings = Record<string, unknown>; // 初始空容器,对应你想要的R.Do const Do = {} as Bindings; // 自定义bind函数:接收键名和依赖已有绑定生成值的函数 function bind<K extends string, V, B extends Bindings>( key: K, valueFn: (bindings: B) => V ) { return (currentBindings: B): B & Record<K, V> => { const value = valueFn(currentBindings); return { ...currentBindings, [key]: value }; }; }
2. 重构你的getZ函数
用上面的工具函数,你可以完全按照最初的预期写法实现,没有任何冗余包装:
// 假设已有这些类型和函数定义 type A = /* 你的A类型 */; type B = /* 你的B类型 */; type C = /* 你的C类型 */; type D = /* 你的D类型 */; function getB(a: A): B { /* 实现逻辑 */ } function getC(b: B): C { /* 实现逻辑 */ } function getD(c: C): D { /* 实现逻辑 */ } type Z = { a: A, b: B, c: C, d: D, }; const getZ = (a: A): Z => pipe( Do, bind('a', () => a), bind('b', ({ a }) => getB(a)), bind('c', ({ b }) => getC(b)), bind('d', ({ c }) => getD(c)), ) as Z;
3. 方案优势
- 无冗余代码:不需要任何
IO.of()/O.some()这类包装,所有操作都是纯同步函数 - 保留中间值:每个
bind都能直接访问之前绑定的所有属性,满足后续转换需求 - 类型安全:TypeScript能正确推导绑定过程中的类型,最后通过类型断言得到最终的
Z类型(也可以优化类型定义让推导更自动)
备选方案:用fp-ts的Identity Monad
如果你不想自己实现工具,也可以用fp-ts中最轻量化的Identity Monad,它只是一个无任何额外语义的包装,运行时开销极小:
import * as I from 'fp-ts/Identity'; const getZ = (a: A): Z => pipe( I.Do, I.bind('a', () => I.of(a)), I.bind('b', ({ a }) => I.of(getB(a))), I.bind('c', ({ b }) => I.of(getC(b))), I.bind('d', ({ c }) => I.of(getD(c))), (identity) => identity.value, );
内容的提问来源于stack exchange,提问作者Manav Chawla
相关产品推荐
相关产品推荐

