如何在TypeScript中为动态长度的函数序列定义类型关系?
实现支持动态函数数组的callExample类型标注
问题描述
我希望创建一个接收函数数组的callExample函数,数组中的每个函数会按顺序执行,执行结果会和其他数据一起传递给下一个函数。示例如下:
callExample([ (stuff) => 123, (stuff, previousResult) => previousResult ** 2, (stuff, previousResult) => String(previousResult) ])
我希望为该逻辑添加类型标注,明确previousResult的类型,并让callExample的返回值类型为数组中最后一个函数的返回类型。
我知晓如下针对固定长度数组的类型定义方式:
type Example<A, B, C> = ([ (stuff: unknown) => A, (stuff: unknown, previous: A) => B, (stuff: unknown, previous: B) => C, ]) => C
但想了解是否存在一种方式,能够定义这种类型关系本身,同时支持动态数量的函数项?
解决方案
可以用TypeScript的递归元组类型实现动态函数链的类型推导,核心是通过递归依次约束每个函数的输入(前一个函数的返回值)和输出,并自动推导最终返回类型。
1. 核心类型定义
首先定义两个辅助类型,分别用于约束函数数组的合法性和提取最终返回类型:
// 提取函数链的最终返回类型 type ChainReturnType<Fns extends any[]> = Fns extends [ (...args: any[]) => infer R, ...infer Rest ] ? Rest extends [(stuff: unknown, previous: R) => infer NextR, ...infer Rest2] ? ChainReturnType<[(stuff: unknown, previous: R) => NextR, ...Rest2]> : R : never; // 约束函数数组的类型:确保每个后续函数的previousResult匹配前一个的返回值 type ValidFunctionChain<Fns extends any[]> = Fns extends [ (stuff: unknown) => infer R, ...infer Rest ] ? Rest extends [(stuff: unknown, previous: R) => infer NextR, ...infer Rest2] ? [(stuff: unknown) => R, ...ValidFunctionChain<[(stuff: unknown, previous: R) => NextR, ...Rest2]>] : Fns : never;
2. 实现callExample函数
将类型约束应用到函数上,同时实现执行逻辑:
function callExample<Fns extends ValidFunctionChain<Fns>>( fns: Fns ): ChainReturnType<Fns> { let previousResult: any; // 实际场景中stuff可作为参数传入,这里用unknown示例 const stuff: unknown = {}; for (const fn of fns) { previousResult = previousResult === undefined ? fn(stuff) : fn(stuff, previousResult); } return previousResult as ChainReturnType<Fns>; }
3. 测试验证
- 正常使用场景:类型自动推导,返回值类型为最后一个函数的返回类型
// result的类型为string const result = callExample([ (stuff) => 123, (stuff, previousResult) => previousResult ** 2, (stuff, previousResult) => String(previousResult) ]);
- 类型错误场景:当后续函数的previousResult类型不匹配时,TypeScript会直接报错
// 报错:previousResult是string类型,无法执行加法操作 callExample([ (stuff) => 'hello', (stuff, previousResult) => previousResult + 1 ]);
关键说明
- 递归类型会自动遍历函数数组,严格校验每个函数的参数类型与前一个函数的返回值类型匹配。
ChainReturnType递归提取最后一个函数的返回类型,确保callExample的返回值类型准确。- 函数实现中的
stuff可以根据实际需求调整类型(比如改为泛型参数),这里用unknown作为通用示例。
内容的提问来源于stack exchange,提问作者Scott Page
相关产品推荐
相关产品推荐

