You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:23:10