ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Effect v4 中 Pipeable 的演进:Pipeable.Class 从 v3 移植与类实例链式 pipe 实战指南

Effect v4 中 Pipeable 的演进:Pipeable.Class 从 v3 移植与类实例链式 pipe 实战指南 Effect v4 中 Pipeable 的演进Pipeable.Class 从 v3 移植与类实例链式 pipe 实战指南【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect本篇技术文章围绕仓库中待发布的变更说明文件 .changeset/pre/cold-knives-lie.md 展开该文件记录了effect包一项 patch 级别变更——将Pipeable.Class从 v3 移植到 v4。读完后你将理解 Effect 中方法式pipe组合的完整实现机制Pipeable接口、pipeArguments辅助函数、Prototype/Class/Mixin三种复用方式知道如何让自己的任意类支持instance.pipe(f, g, h)链式调用并能看懂仓库内Data.Class等核心类型如何依赖这套机制。变更记录本身changesets 工作流中的 patch 项该文档位于 Effect 仓库的.changeset/pre/目录下遵循 changesets 发布工作流YAML frontmatter 中声明effect: patch正文一句话概括为PortPipeable.Classfrom v3.并附上两段最小可运行示例。这条变更并非孤立存在。从 packages/effect/CHANGELOG.md 中可以确认PortPipeable.Classfrom v3 的内容被收录在4.0.0-beta.6的 Patch Changes 段落中对应 PR #1323。也就是说.changeset/pre/中这份文件是 v4 beta 系列累积待发布变更的落盘记录其示例与 CHANGELOG 中的发布说明逐字一致可以作为该 API 语义的官方定义依据。原文档示例一从零定义一个 pipeable 类changeset 文档给出的第一段示例演示了直接继承Pipeable.Class()定义新类的完整写法class MyClass extends Pipeable.Class() { constructor(public a: number) { super() } methodA() { return this.a } } console.log(new MyClass(2).pipe((x) x.methodA())) // 2要点拆解类通过extends Pipeable.Class()获得pipe方法实例new MyClass(2)可以直接调用.pipe(...).pipe()的第一个参数接收实例本身示例中形参写作x把this.a通过methodA()读出来最终输出2子类的构造函数必须显式调用super()无参这是继承Pipeable.Class()的约束。原文档示例二把既有类提升为 pipeable 类第二段示例演示了继承一个已有类A同时为其附加pipe能力形成新的组合类Bclass A { constructor(public a: number) {} methodA() { return this.a } } class B extends Pipeable.Class(A) { constructor(private b: string) { super(b.length) } methodB() { return [this.b, this.methodA()] } } console.log(new B(pipe).pipe((x) x.methodB())) // [pipe, 4]这里展示了该移植 API 在 v3 中的双重角色无参形式Pipeable.Class()作为空基类为任意新类注入pipe有参形式Pipeable.Class(A)接收一个既有类构造器返回一个保留了A的构造器与实例成员、并额外具备pipe的子类。B的构造函数把b.length传给父级Asuper(b.length)因此methodA()能访问到this.a 4methodB()组合后输出[pipe, 4]。需要说明的适用前提上述有参形式是 changeset即 v4 beta 阶段移植落地时记录的 API 用法。而从当前 HEAD 的源码结构看包裹既有类注入 pipe的能力由后文介绍的Pipeable.Mixin承载迁移 v3 代码时建议对照当前源码确认目标形式。源码剖析pipe 组合的底层实现上述行为的实现全部集中在 packages/effect/src/Pipeable.ts该模块自 v2.0.0 起提供共享的Pipeable接口与实现辅助模块注释明确其定位让值可以以value.pipe(f, g, h)形式从左到右依次经过一系列一元函数替代深层嵌套调用。Pipeable 接口方法式组合的类型契约Pipeable是一个 interfacePipeable.ts#L44通过大量重载描述pipe方法的组合语义无参形式pipeA(this: A): A不调用任何函数时返回this本身保证value.pipe()是合法的幂等操作逐元组重载从 1 个函数到二十余个函数逐级展开每一级形参为ab: (_: A) B, bc: (_: B) C, ...返回最终类型。重载逐类型显式展开而非变长参数是为了让 TypeScript 在长链条中精确推断每一段的类型而不是退化为any。模块 JSDoc 中的官方示例展示了它在Effect上的典型用法注意.pipe是方法式写法与函数式pipe(value, f, g)等价但起点是值本身import { Effect } from effect const program Effect.succeed(1).pipe( Effect.map((x) x 1), Effect.flatMap((x) Effect.succeed(x * 2)) ) Effect.runSync(program) // 4pipeArguments变参 pipe 的运行时分发接口只是类型层运行时的真正实现是pipeArgumentsPipeable.ts#L564-L594export const pipeArguments A(self: A, args: IArguments): unknown { switch (args.length) { case 0: return self case 1: return args0 case 2: return args1) case 3: return args2)) // ... case 4 ~ 9 逐级内联展开 default: { let ret self for (let i 0, len args.length; i len; i) { ret argsi } return ret } } }两个值得注意的实现细节对 09 个函数使用switch分支做手动内联展开避免循环开销是典型的热点路径优化超过 9 个才落入for循环兜底它接收 JavaScript 的arguments对象IArguments因此专为类方法中实现自定义.pipe(...)这一场景设计——在方法体内可以直接把arguments传进来。Prototype / Class / Mixin三种复用方式changeset 示例中Pipeable.Class的具体形态以及 v4 新增的配套工具都定义在同一文件中导出位置作用引入版本PrototypePipeable.ts#L607-L611一个可复用原型对象其pipe()直接委托给pipeArguments(this, arguments)3.15.0ClassPipeable.ts#L625-L629可直接extends的基类构造器原型即Prototype3.15.0PipeableConstructorPipeable.ts#L646-L648构造器侧类型new(...args) Pipeable用于把某值是 pipeable 类的构造器表达进类型系统3.15.0MixinPipeable.ts#L669-L675接收既有类TBase返回TBase PipeableConstructor的子类注入的pipe同样委托pipeArguments4.0.0其中Class的实现是一个 IIFE 包装的空基类export const Class: new() Pipeable (function() { function PipeableBase() {} PipeableBase.prototype Prototype return PipeableBase as any })()而Mixin则直接以继承方式包裹传入的类export const Mixin TBase extends new(...args: ReadonlyArrayany) any( klass: TBase ): TBase PipeableConstructor (class extends klass { pipe() { return pipeArguments(this, arguments) } })从源码结构看Mixin的 JSDoc 明确写着为既有类添加 pipe 支持而无需继承基类或修改其原型其返回类型TBase PipeableConstructor保留了原构造器签名——这正是 changeset 示例二中Pipeable.Class(A)所扮演的角色在 v4 源码中的对应物。如果你从 v3 迁移Pipeable.Class(A)风格的代码可以先查看Pipeable.Mixin的当前行为与类型约束再决定改写方式。仓库内的真实用法Data 类与查询构造器这套机制不是孤立的工具 API而是 Effect 核心数据类型 pipeable 能力的公共底座仓库中有两处典型使用1.Data.Class直接继承Pipeable.Class。在 packages/effect/src/Data.ts 中不可变数据类型的基类被声明为export const Class: newA extends Recordstring, any {}(...) ReadonlyA Pipeable.Pipeable class extends Pipeable.Class { constructor(props: object | undefined) { super() if (props) { InternalRecord.assignProperties(this, props) } } } as any返回值类型ReadonlyA Pipeable.Pipeable说明所有通过Data.Class定义的数据类实例天然具备Pipeable接口契约——这与 CHANGELOG 中同期变更MakeData.Class,Data.TaggedClass, andCause.YieldableErrorpipeable相互印证。2.Prototype被展开到普通对象原型上。在 packages/platform/browser/src/IndexedDbQueryBuilder.ts 中浏览器平台的 IndexedDB 查询构造器通过对象展开复用 pipe 实现...Pipeable.Prototype,这说明Prototype的设计意图当类或对象原型需要标准 pipe 实现时可复用此值在 platform 包内确有落地场景。小结迁移与使用的核对清单结合 changeset 文档与当前源码围绕Pipeable.Class移植这项变更可以沉淀出如下核对清单语义核对移植的核心是让类实例成为pipe组合的合法起点value.pipe(f, g, h)从左到右依次应用无参pipe()返回this对应pipeArguments的case 0分支API 形态核对以 packages/effect/src/Pipeable.ts 当前导出为准——空基类用extends Pipeable.Class包裹既有类用Pipeable.Mixinsince 4.0.0原型对象直接展开Pipeable.Prototype版本前提changeset 声明这是effect包的 patch 变更且 CHANGELOG 显示该内容随4.0.0-beta.6进入 v4 beta 线因此示例行为以 v4effect-smol代码线为准与 v3 稳定版的 API 名称可能存在差异组合上限类型层面重载覆盖二十余个组合函数运行时超过 9 个函数自动进入循环路径两者共同保证了长链条的类型安全与运行效率。至此从一份 changeset 补丁说明出发我们完整走通了Pipeable从接口契约、运行时分发到仓库内真实用法的三层实现这也正是 Effect 让任意类皆可链式组合这一能力的全部技术脉络。【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表