TypeScript递归映射可选可空类型 实现自定义类型转换
TypeScript 类型转换优化方案
核心优化点
- 简化可空/可选修饰保留逻辑:利用分布式条件类型自动处理联合类型的null/undefined透传,删除冗余的多分支判断
- 支持批量传入转换规则:无需嵌套调用,直接传入转换规则数组即可批量处理多组类型替换
完整实现代码
// 原有基础类型定义 type DateJson = { __type: 'Date'; iso: string; } interface Pointer { __type: 'Pointer'; className: string; objectId: string; } interface ParseObject { __type: 'Object'; className: string; } // 转换规则类型定义 type ReplaceRule = [source: unknown, target: unknown] // 单组转换规则的递归替换 type DeepReplaceSingle<T, S, R> = { [K in keyof T]: T[K] extends null | undefined ? T[K] : T[K] extends S ? R : T[K] extends Record<string, unknown> ? DeepReplaceSingle<T[K], S, R> : T[K] } // 多组转换规则的批量递归替换 type DeepReplace<T, Rules extends ReplaceRule[]> = Rules extends [infer FirstRule extends ReplaceRule, ...infer RestRules extends ReplaceRule[]] ? DeepReplace<DeepReplaceSingle<T, FirstRule[0], FirstRule[1]>, RestRules> : T // 最终使用的转换类型,新增转换规则直接在数组中添加即可 type ParseAttributes<T> = DeepReplace<T, [ [Pointer, ParseObject], [DateJson, Date] ]>
效果验证
用你提供的测试类型验证:
type Test = { user: Pointer; employee?: { pointer?: Pointer | null; name: string; company: string; }; date?: DateJson; other: { date: DateJson | null; testKey: number; }; nested: { date: DateJson; deep: { pointer: Pointer | null another: { test?: string; date?: DateJson | null } } } } // 转换后的结果和你期望的输出完全一致 type ConvertedTest = ParseAttributes<Test>
扩展说明
后续新增需要转换的类型时,只需在ParseAttributes的规则数组中新增对应[源类型, 目标类型]项即可,无需修改核心递归逻辑。默认递归深度足够覆盖常规业务场景的嵌套层级需求。
内容的提问来源于stack exchange,提问作者Hari Prasad
相关产品推荐
相关产品推荐

