如何在TypeScript类型层面验证Mapper链数组的合法性?
TypeScript 链式Mapper类型验证实现方案
这个需求完全可以实现,通过TypeScript的递归条件类型和元组类型推导,就能在类型层面强制约束Mapper链的输入输出衔接关系。
核心类型定义
interface Mapper<From, To> { map(from: From): To; } // 辅助类型:定义链式Mapper的元组结构 type ChainableMappers<Start, End> = // 基础情况:单个Mapper直接连接Start和End | [Mapper<Start, End>] // 递归情况:第一个Mapper输出Mid,剩余元组必须是从Mid到End的链式Mapper | [Mapper<Start, infer Mid>, ...ChainableMappers<Mid, End>]; // 对外暴露的链式Mapper类型 type ChainedMappers<From, To> = ChainableMappers<From, To>;
测试示例
// 定义测试类型 type A = { type: 'A' }; type B = { type: 'B' }; type C = { type: 'C' }; type D = { type: 'D' }; // 实现各个Mapper const mapperAB: Mapper<A, B> = { map: (a) => ({ type: 'B' }) }; const mapperBC: Mapper<B, C> = { map: (b) => ({ type: 'C' }) }; const mapperCD: Mapper<C, D> = { map: (c) => ({ type: 'D' }) }; // ✅ 合法的链式Mapper数组:类型验证通过 const correctMappers: ChainedMappers<A, D> = [ mapperAB, mapperBC, mapperCD, ]; // ❌ 非法的链式Mapper数组:类型验证失败(mapperCD的输入类型C与前一个输出类型B不匹配) const incorrectMappers: ChainedMappers<A, D> = [ mapperAB, // 缺失mapperBC导致类型断裂 mapperCD, ];
原理说明
- 递归类型
ChainableMappers通过两种分支覆盖所有合法链式场景:单个Mapper的简单链,以及多个Mapper组成的递归链。 - 利用
infer关键字自动推导相邻Mapper之间的中间类型Mid,强制要求下一个Mapper的输入类型必须等于前一个的输出类型。 - TypeScript会在编译阶段自动检查整个数组的类型衔接,一旦出现类型断裂就会抛出错误。
版本要求
需要使用TypeScript 4.1及以上版本,该实现依赖递归条件类型和元组剩余元素推导特性。
内容的提问来源于stack exchange,提问作者doup
相关产品推荐
相关产品推荐

