如何为TypeScript链式模块定义类型以保证中间类型匹配?
实现类型安全的ModuleChain链式集合
首先定义基础的Module类型:
type Module<TInput, TOutput> = { passThrough: (input: TInput) => TOutput; };
需求说明
需要创建ModuleChain类型,用于存储上述模块的链式集合,要求链中相邻模块的输出/输入类型必须匹配:
- 合法示例:
[Module<string, number>, Module<number, Date>, Module<Date, string>] - 非法示例:
[Module<string, number>, Module<Date, string>](中间类型不匹配)
以下提供两种可行方案:
方案一:扁平数组版本(只读元组)
利用TypeScript的递归条件类型和可变元组类型,可以定义出类型安全的数组版ModuleChain:
type ModuleChain<TInput, TOutput> = // 基础情况:单个模块,直接匹配输入输出类型 readonly [Module<TInput, TOutput>] // 递归情况:第一个模块的输出作为后续链的输入 | readonly [Module<TInput, infer TIntermediate>, ...ModuleChain<TIntermediate, TOutput>];
使用示例
const moduleA: Module<string, number> = { passThrough: (s) => parseInt(s) }; const moduleB: Module<number, Date> = { passThrough: (n) => new Date(n) }; const moduleC: Module<Date, string> = { passThrough: (d) => d.toISOString() }; const moduleD: Module<string, string> = { passThrough: (s) => s.toUpperCase() }; // 合法:类型匹配 const chain1: ModuleChain<string, string> = [moduleA, moduleB, moduleC, moduleD]; const chain2: ModuleChain<string, Date> = [moduleA, moduleB]; // 非法:类型不匹配,TypeScript会报错 const badChain: ModuleChain<string, string> = [moduleA, moduleC];
方案二:解决类实现的问题
针对你提到的类实现的两个痛点,我们可以拆分基础链和链式结构,并通过辅助函数自动推断中间类型:
1. 定义链结构类
// 基础链:仅包含单个模块,无后续节点 class SingleModuleChain<TInput, TOutput> { constructor(public module: Module<TInput, TOutput>) {} // 执行链式调用 passThrough(input: TInput): TOutput { return this.module.passThrough(input); } } // 链式节点:包含头部模块和后续链 class LinkedModuleChain<TInput, TIntermediate, TOutput> { constructor( public head: Module<TInput, TIntermediate>, public tail: SingleModuleChain<TIntermediate, TOutput> | LinkedModuleChain<TIntermediate, any, TOutput> ) {} passThrough(input: TInput): TOutput { const intermediate = this.head.passThrough(input); return this.tail.passThrough(intermediate); } } // 统一对外的类型别名 type ModuleChainClass<TInput, TOutput> = | SingleModuleChain<TInput, TOutput> | LinkedModuleChain<TInput, any, TOutput>;
2. 辅助函数简化创建
通过函数重载和递归调用,自动推断中间类型,无需手动指定:
// 函数重载:支持1个、2个、3个...模块的链式创建 function chain<TInput, TOutput>(module: Module<TInput, TOutput>): SingleModuleChain<TInput, TOutput>; function chain<TInput, TIntermediate, TOutput>( first: Module<TInput, TIntermediate>, second: Module<TIntermediate, TOutput> ): LinkedModuleChain<TInput, TIntermediate, TOutput>; function chain<TInput, T1, T2, TOutput>( first: Module<TInput, T1>, second: Module<T1, T2>, third: Module<T2, TOutput> ): LinkedModuleChain<TInput, T1, TOutput>; // 扩展更多参数的重载(按需添加) function chain(...modules: any[]): any { if (modules.length === 1) { return new SingleModuleChain(modules[0]); } const head = modules[0]; const tail = chain(...modules.slice(1)); return new LinkedModuleChain(head, tail); }
使用示例
// 自动推断类型,无需手动指定泛型 const chainClass1 = chain(moduleA, moduleB, moduleC, moduleD); // 调用链式处理 const result = chainClass1.passThrough("123"); // 类型为string // 非法情况:传入类型不匹配的模块,TypeScript会直接报错 const badChainClass = chain(moduleA, moduleC);
内容的提问来源于stack exchange,提问作者Tim Leach
相关产品推荐
相关产品推荐

