如何序列化Typescript类型信息并从序列化结果恢复io-ts的Type对象
解决方案
1. 反序列化io-ts Type对象的实现思路
你提到的序列化后的io-ts Type结构自带_tag标识字段,完全可以通过递归匹配该字段还原对应的io-ts运行时类型,下面是可直接运行的最简实现:
import * as t from 'io-ts' // 先定义序列化后的io-ts类型结构 interface SerializedIoTsType { _tag: string name: string props?: Record<string, SerializedIoTsType> type?: SerializedIoTsType // 数组元素类型 types?: SerializedIoTsType[] // 联合类型成员 } // 反序列化核心函数 function deserializeType(serialized: SerializedIoTsType): t.Any { switch (serialized._tag) { // 基础类型 case 'NumberType': return t.number case 'StringType': return t.string case 'BooleanType': return t.boolean case 'NullType': return t.null case 'UndefinedType': return t.undefined // 复合类型 case 'ArrayType': return t.array(deserializeType(serialized.type!)) case 'InterfaceType': const props = Object.fromEntries( Object.entries(serialized.props!) .map(([k, v]) => [k, deserializeType(v)]) ) return t.type(props, serialized.name) case 'UnionType': const unionMembers = serialized.types!.map(deserializeType) as [t.Any, t.Any, ...t.Any[]] return t.union(unionMembers, serialized.name) // 用到其他io-ts类型(比如字面量、元组、交叉类型)直接在这里补case即可 default: throw new Error(`不支持的io-ts类型:${serialized._tag}`) } }
2. 整套跨进程类型校验的落地流程
因为原生TS类型编译后会被擦除,所以不可能直接从TS类型反向生成运行时类型,你可以基于io-ts和上面的反序列化函数实现你要的理想接口:
- 定义侧(事件生产方):统一用io-ts定义事件类型,既可以通过
t.TypeOf推导得到原生TS类型,也可以直接序列化io-ts对象传给对端 - 注册阶段:生产方调用
register接口时,序列化事件的io-ts对象传给消费方,消费方反序列化后存入本地事件类型映射表 - 发送阶段:生产方传事件时,TS层面会自动约束输入符合类型定义,消费方收到事件后用存储的io-ts类型做运行时校验,不符合直接返回错误
封装后的ContentGateway示例实现:
import * as t from 'io-ts' import * as E from 'fp-ts/Either' interface ContentGateway { // 注册:传入io-ts类型对象,内部自动序列化传输 register: <T extends t.Any>(eventType: T) => E.Either<Error, void>; // 发送:传入io-ts类型对象和事件数据,TS编译阶段自动校验类型 send: <T extends t.Any>(eventSchema: T, event: t.TypeOf<T>) => E.Either<Error, void>; }
3. 注意事项
如果你的场景用到自定义branded类型、递归类型等复杂io-ts类型,只需要在反序列化函数中补充对应的_tag匹配逻辑即可,确保两端的自定义类型实现一致。
内容的提问来源于stack exchange,提问作者Adam A
相关产品推荐
相关产品推荐

