如何定义参数为前序回调返回值合并类型的可变参回调函数
实现类型安全的
specialFunction:链式回调的合并参数约束 需求是实现一个specialFunction,可以接收任意数量的回调函数,每个回调的唯一参数必须是之前所有回调返回值的合并类型,同时不能硬编码参数数量。期望的调用行为如下:
// 合法调用:无类型错误 specialFunction( () => ({a: 1}), (arg) => { console.log(arg.a) return { b: 2} }, (arg) => { console.log(arg.a) console.log(arg.b) } ) // 非法调用:触发TypeScript错误 specialFunction( () => ({a: 1}), (arg) => { console.log(arg.b) // 错误:arg上不存在b属性 return { b: 2} }, (arg) => { console.log(arg.a) console.log(arg.c) // 错误:arg上不存在c属性 } )
之前尝试的代码无法正确推导第三个回调的参数类型,下面是可行的解决方案:
完整实现代码
// 合并两个对象类型,后一个类型的键会覆盖前一个 type Merge<A, B> = Omit<A, keyof B> & B; // 递归构建链式回调的类型数组 type ChainCallbacks< T extends unknown[] = [], Acc = {} > = T extends [infer First, ...infer Rest] ? First extends (arg: infer Arg) => infer Ret ? Arg extends Acc ? [(arg: Acc) => Ret, ...ChainCallbacks<Rest, Merge<Acc, Ret>>] : never : never : []; const specialFunction = <T extends unknown[]>( ...callbacks: ChainCallbacks<T> ) => { let mergedResult: Record<string, unknown> = {}; for (const cb of callbacks) { const result = cb(mergedResult as any); if (result) { mergedResult = {...mergedResult, ...result}; } } return mergedResult; };
代码解释
Merge类型:用于合并两个对象类型,如果存在重复键,后面的类型会覆盖前面的,保证最新的返回值属性优先。ChainCallbacks类型:递归遍历回调数组,为每个回调指定参数类型为之前所有返回值的合并结果(Acc累加器),同时将当前回调的返回值合并到累加器中,传递给下一个回调。specialFunction函数:接收符合ChainCallbacks类型约束的回调数组,执行时维护一个合并结果对象,依次调用每个回调并更新合并结果。
测试验证
// 合法调用:完全符合类型约束 specialFunction( () => ({a: 2}), ({a}) => ({b: a + 1}), // arg类型为{a: number} ({a, b}) => ({c: a + b}) // arg类型为{a: number, b: number} ); // 非法调用:触发类型错误 specialFunction( () => ({a: 2}), ({b}) => ({c: 3}), // 错误:arg上不存在b属性 ({d}) => ({e: 4}) // 错误:arg上不存在d属性 );
内容的提问来源于stack exchange,提问作者TaggedLiteral
相关产品推荐
相关产品推荐

