首页/新闻资讯/正文详情

fp-ts Json 模块完全指南:基于 Either 的安全 JSON 解析与序列化

发布时间:2026/9/23 23:45:07 来源:云帆数科 栏目:资讯中心
fp-ts Json 模块完全指南:基于 Either 的安全 JSON 解析与序列化
fp-ts Json 模块完全指南基于 Either 的安全 JSON 解析与序列化【免费下载链接】fp-tsFunctional programming in TypeScript项目地址: https://gitcode.com/gh_mirrors/fp/fp-ts导读fp-ts/Json模块自 v2.10.0 起提供为 TypeScript 函数式编程提供了不抛异常的 JSON 解析与序列化方案它把 JavaScript 内置的JSON.parse/JSON.stringify包装成返回Eitherunknown, Json的纯函数让错误成为可组合、可追踪的一等公民。读完本文你将掌握Json、JsonArray、JsonRecord三个核心类型的准确含义学会用parse安全解析字符串、用stringify安全序列化任意值并能通过pipe、Either的各种组合子把它们无缝接入 fp-ts 的任意函数式管线中。一、模块概览为什么 JSON 操作需要函数式封装JavaScript 原生的JSON.parse与JSON.stringify是可能抛异常的函数解析一段非法 JSON 会抛出SyntaxError序列化含循环引用的对象会抛出TypeError。在 fp-ts 的编程范式里异常流无法被pipe、map、chain等组合子感知会破坏类型的纯净性。Json模块给出的答案是用 tryCatch位于src/Either.ts把这两个 API 包装成返回Eitherunknown, Json的纯函数。tryCatch的核心实现非常直白见 src/Either.ts#L1393-L1399export const tryCatch E, A(f: LazyArgA, onThrow: (e: unknown) E): EitherE, A { try { return right(f()) } catch (e) { return left(onThrow(e)) } }即正常返回right(结果)任何异常都经onThrow转换后放入left。Json模块传给onThrow的是identity见 src/Json.ts因此错误类型就是unknown原始异常对象如SyntaxError、TypeError会被原样保留在Either的左侧供后续mapLeft精确检查。从模块导出看src/index.ts在第 58 行import * as json from ./Json、第 385 行将整个模块作为json命名空间导出因此你可以用import * as J from fp-ts/Json或import { json } from fp-ts两种方式引入。二、类型体系Json / JsonArray / JsonRecordJson模块定义了三个互相递归的类型完整刻画了合法 JSON 值的形态见 src/Json.ts#L10-L22export type Json boolean | number | string | null | JsonArray | JsonRecord export interface JsonRecord { readonly [key: string]: Json } export interface JsonArray extends ReadonlyArrayJson {}类型定义说明Jsonboolean \| number \| string \| null \| JsonArray \| JsonRecordJSON 值的联合类型即值层面的完整定义JsonRecordreadonly [key: string]: Json键为字符串、值为Json的只读记录即 JSON 对象JsonArrayextends ReadonlyArrayJsonJson元素的只读数组即 JSON 数组几个值得注意的设计细节没有undefined、函数、Symbol、bigint这些都不是合法 JSON 值因而被类型系统直接排除。dtslint/Json.ts中用ts-expect-error断言了undefined、箭头函数、Symbol()、含undefined字段的对象等都无法通过stringifyJson的类型检查见 dtslint/Json.ts#L9-L20。对象与数组是只读readonly形态JsonRecord的索引签名和JsonArray的数组类型都带readonly与 fp-ts 一贯倡导的不可变数据结构风格一致也方便与ReadonlyArray、ReadonlyRecord等模块对接。递归结构Json引用JsonArray与JsonRecord而后两者又引用Json从而支持任意深度的嵌套 JSON对象套数组、数组套对象……。三、parse安全解析 JSON 字符串parse将一段 JSON 字符串转换为Json类型对应JSON.parse其签名与实现如下export declare const parse: (s: string) Eitherunknown, Json // 实现src/Json.ts#L37 export const parse (s: string): Eitherunknown, Json tryCatch(() JSON.parse(s), identity)行为语义输入合法 JSON→ 返回E.right(json)其中json已被JSON.parse反序列化为实际 JavaScript 值输入非法 JSON→ 底层JSON.parse抛出SyntaxError被tryCatch捕获后包装为E.left(syntaxError)异常对象本身原样保留。官方示例可直接运行import * as J from fp-ts/Json import * as E from fp-ts/Either import { pipe } from fp-ts/function assert.deepStrictEqual(pipe({a:1}, J.parse), E.right({ a: 1 })) assert.deepStrictEqual( pipe({a:}, J.parse), E.left(new SyntaxError(Unexpected token }, {a:} is not valid JSON)) )上面第二个断言展示了一个关键事实解析失败的left分支携带的是真实的SyntaxError实例其message与原生JSON.parse抛出的完全一致便于日志记录或mapLeft分类处理。测试验证在 test/Json.ts#L7-L13 中这两个场景均被测试用例覆盖it(parse, () { U.deepStrictEqual(pipe({a:1}, _.parse), E.right({ a: 1 })) U.deepStrictEqual( pipe({a:}, _.parse), E.left(new SyntaxError(Unexpected token }, {a:} is not valid JSON)) ) })四、stringify安全序列化任意 JavaScript 值stringify将任意 JavaScript 值转换为 JSON 字符串对应JSON.stringify签名与实现如下export declare const stringify: A(a: A) Eitherunknown, string // 实现src/Json.ts#L60-L67 export const stringify A(a: A): Eitherunknown, string tryCatch(() { const s JSON.stringify(a) if (typeof s ! string) { throw new Error(Converting unsupported structure to JSON) } return s }, identity)行为语义与裸用JSON.stringify相比stringify有两个层次的保护异常捕获JSON.stringify遇到循环引用时会抛出TypeError: Converting circular structure to JSON该异常被tryCatch捕获并放入left。返回类型守卫JSON.stringify在遇到undefined、函数或Symbol作为顶层输入时会返回undefined而非字符串。实现里显式检查typeof s ! string一旦出现这种情况就抛出new Error(Converting unsupported structure to JSON)从而保证right分支永远是真正的字符串杜绝看似成功实则拿到 undefined的隐性 bug。官方示例可直接运行import * as E from fp-ts/Either import * as J from fp-ts/Json import { pipe } from fp-ts/function assert.deepStrictEqual(J.stringify({ a: 1 }), E.right({a:1})) const circular: any { ref: null } circular.ref circular assert.deepStrictEqual( pipe( J.stringify(circular), E.mapLeft((e) e instanceof Error e.message.includes(Converting circular structure to JSON)) ), E.left(true) )第二个断言展示了stringify与E.mapLeft的经典配合序列化失败不再是静默的运行时异常而是可以被函数式地检查、映射与分支处理。测试验证test/Json.ts#L15-L35 覆盖了四种典型输入输入期望结果{ a: 1 }E.right({a:1})含循环引用的对象E.left(...)且message含Converting circular structure to JSON类型化对象{ name: Giulio, age: 45 }E.right({name:Giulio,age:45})undefined顶层E.left(new Error(Converting unsupported structure to JSON))其中最后一个用例直接验证了返回类型守卫分支_.stringify(undefined as any)必须返回E.left(new Error(Converting unsupported structure to JSON))。类型层面的约束虽然stringify的类型签名是A(a: A) Eitherunknown, string接受任意类型但配合Json类型使用时可获得更强的编译期保障。dtslint/Json.ts展示了类型测试的意图以下调用必须报类型错误ts-expect-errorstringifyJson(undefined)、stringifyJson(() {})、stringifyJson(Symbol())、stringifyJson({ a: undefined })见 dtslint/Json.ts#L9-L20而合法的 JSON 形状如{ a: a, b: 1 }及其数组、展开副本可以顺利通过见 dtslint/Json.ts#L22-L37。五、组合使用把 parse / stringify 接入函数式管线由于parse与stringify都返回Either它们可以无缝接入 fp-ts 的Either组合子体系。官方示例和 dtslint 用例给出了典型用法1. 链式校验与转换import * as E from fp-ts/Either import { pipe } from fp-ts/function // 解析 → 校验 → 转换全程类型安全 const result pipe( {a:1}, J.parse, E.chain((json) /* 在这里对 json 做进一步校验/转换返回 Eitherunknown, X */ E.right(json)), E.map((x) /* 转换成功后的值 */ x) )2. 用 chainFirst 挂接副作用dtslint 中的用例pipe(E.right(a), E.chainFirst(_.stringify))见 dtslint/Json.ts#L39-L40表明stringify可直接用于chainFirst在保持左侧值不变的同时把序列化结果作为校验步骤——若序列化失败整个管道立即短路为left。// $ExpectType Eitherunknown, string pipe(E.right(a), E.chainFirst(_.stringify))3. 错误分类处理const classify (e: unknown): string e instanceof SyntaxError ? JSON 语法错误: ${e.message} : e instanceof Error ? 其他错误: ${e.message} : 未知错误: ${String(e)} const safeParse (s: string) pipe(s, J.parse, E.mapLeft(classify))六、与其他模块的关系及版本背景依赖Json模块仅依赖EithertryCatch与functionidentity依赖面极小可放心引入见 src/Json.ts#L4-L5。版本引入该模块于 v2.10.0 加入CHANGELOG 中 addJsonmodule 条目。CHANGELOG 同时记录了后续版本中原先分散在其他模块的Json类型、parseJSON、stringifyJSON等旧 API 被标记废弃官方明确建议使用Json模块替代见 CHANGELOG.md。因此新代码应统一从fp-ts/Json导入。七、小结与使用建议fp-ts/Json模块的价值在于把最容易悄悄抛异常的两个 JSON 操作变成了显式、可组合、类型可追踪的Either计算。核心要点回顾Json/JsonArray/JsonRecord三个递归类型精确刻画了合法 JSON 值天然排除undefined、函数等非法输入parse返回Eitherunknown, Json解析失败时左侧携带原始SyntaxErrorstringify返回Eitherunknown, string既捕获循环引用异常又用显式检查杜绝顶层值为 undefined 却返回非字符串的隐患二者均可通过pipe、chain、chainFirst、mapLeft等组合子接入任意 Either 管线错误处理从try/catch 包围升级为数据流中的分支。推荐的使用姿势在解析外部输入HTTP 响应体、配置文件、本地存储读取时一律用J.parseE.mapLeft显式分类错误在序列化可能含循环引用或顶层非字符串值的数据时使用J.stringify并在left分支统一记录日志。这样既保留了原生JSONAPI 的性能与语义又让整个错误路径始终处于类型系统的掌控之中。【免费下载链接】fp-tsFunctional programming in TypeScript项目地址: https://gitcode.com/gh_mirrors/fp/fp-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

嵌入式五大通信接口时序全解析:UART/SPI/I2C/CAN/USB
嵌入式五大通信接口时序全解析:UART/SPI/I2C/CAN/USB

做嵌入式这些年,无论是带新人、做评审,还是自己调板子,来来回回绕不开的问题就那几个:模块之间用什么通信?信号线怎么接?波形为什么不对?我发现自己面试候选人也特别爱问通信接口,因… · 2026/9/23 23:44:48

智能系统门窗怎么选?新手小白看完这篇不踩坑
智能系统门窗怎么选?新手小白看完这篇不踩坑

装修这事儿吧,真是坑一个接着一个。我身边好多朋友,房子装完才发现:瓷砖买贵了能忍,柜子做丑了能忍,唯独窗户没选好,是真的忍不了——冬天窗边冷飕飕,晚上马路上车来车往吵得睡不着,… · 2026/9/23 23:44:42

多微网时空互补调度:基于YALMIP的低碳协同优化方法
多微网时空互补调度:基于YALMIP的低碳协同优化方法

简介:本资源是一套面向低碳经济运行目标的多微网能量互联优化调度MATLAB实现方案,适用于电力系统、新能源与智能微网方向的研究生、科研人员及工程技术人员,解决多微网协同运行中源-荷-储不确定性带来的调度难题。程序以就地消纳为优先原则&a… · 2026/9/23 23:44:36

逻辑回归的概率本质与统计推断:从Sigmoid到Wald检验
逻辑回归的概率本质与统计推断:从Sigmoid到Wald检验

简介:本资源是一份面向人工智能与机器学习初学者及高校学生的理论结合实践型教学文档,聚焦逻辑回归这一经典二分类算法,深入阐释其背后的概率论与数理统计原理。文档系统梳理了Sigmoid函数建模思想、条件概率与贝叶斯定理在参数估计中的作用&… · 2026/9/24 0:16:59

液冷系统专用液位检测:抗污染、抗扰动、高可靠性设计
液冷系统专用液位检测:抗污染、抗扰动、高可靠性设计

1. 为什么液冷散热设备的液位检测不能照搬通用方案?工业级液冷散热系统里,液位检测这件事,表面看只是“知道水在不在”,实则是个精密的系统工程。我最早接触这类项目是在给某新能源电控柜做热管理升级时——客户原用的浮球开关在连… · 2026/9/24 0:16:53

双目避障芯片选型实战:海思Hi5662与Hi5622方案深度对比
双目避障芯片选型实战:海思Hi5662与Hi5622方案深度对比

做机器人视觉避障这一年多,我最大的一个教训是:芯片选型永远不能只看发布会PPT。项目刚开始我们理所当然觉得“算法才是核心,芯片能用就行”,结果在双路MIPI、帧同步、NPU算力和算法部署这些环节上反复返工,烧掉的开发… · 2026/9/24 0:16:47

ESP32换板必看:小智源码板级适配与音频链路调试指南
ESP32换板必看:小智源码板级适配与音频链路调试指南

1. 从一次翻车经历说起:为什么换板子成了“重写项目”去年冬天,我帮一个做智能语音硬件的朋友处理一个紧急问题。他们团队基于小智的源码做了一款带语音交互的桌面机器人,原本在 ESP32-S3-DevKitC 上跑得好好的,产线都小批量试产了… · 2026/9/24 0:16:47

【SSM计算机毕业设计案例】基于 SSM 的网络在线教学视频系统的设计与实现 基于 SSM 的在线课程视频管理系统(程序+文档+讲解+定制)
【SSM计算机毕业设计案例】基于 SSM 的网络在线教学视频系统的设计与实现 基于 SSM 的在线课程视频管理系统(程序+文档+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am… · 2026/9/24 0:16:28

MATLAB深度学习图像超分辨率实战:从ESPCN网络搭建到部署全流程
MATLAB深度学习图像超分辨率实战:从ESPCN网络搭建到部署全流程

简介:这份资源面向图像处理与深度学习方向的初学者及进阶开发者,提供了一套基于卷积神经网络的图像超分辨率完整实现,参考ECCV 2014的SRCNN经典论文,可用于理解从低分辨率到高分辨率图像的重建流程,适合课程设计、算法… · 2026/9/24 0:15:38

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码