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

如何在TypeScript中为含可变数量泛型的函数定义类型?

TypeScript 实现任意数量 Loadable 的合并函数类型定义

给定类型定义

type Loadable<T> = () => T
type LoadableCombinerResult<T> = { result: T }

需求描述

需要定义一个函数类型,满足以下要求:

  • 接收任意数量的 Loadable<ResponseDataType> 输入,每个输入的 ResponseDataType 可以各不相同;
  • 接收一个 combiner 函数,其参数为上述所有 Loadable 的返回值组成的集合;
  • 函数内部会处理 Loadable 的错误状态与加载进度,仅当所有 Loadable 加载成功时才调用 combiner,最终返回 LoadableCombinerResult<TResult> 类型。

当前实现方案

目前在 TypeScript 中只能通过多个重载函数来实现有限数量的参数支持:

function useLoadableCombiner2<TResult, T1, T2>(
  ...args: [Loadable<T1>, Loadable<T2>, (t1: T1, t2: T2) => TResult]
): LoadableCombinerResult<TResult> { /* 实现逻辑 */ }
function useLoadableCombiner3<TResult, T1, T2, T3>(
  ...args: [Loadable<T1>, Loadable<T2>, Loadable<T3>, (t1: T1, t2: T2, t3: T3) => TResult]
): LoadableCombinerResult<TResult> { /* 实现逻辑 */ }
// 更多对应不同参数数量的重载...

问题

能否在 TypeScript 中用单个函数声明完成这个类型定义?也可以用数组/类型元组替代可变参数,核心目标是:传入任意数量的 Loadable 后,combiner 函数能获得正确的类型提示。


解决方案:使用可变元组泛型

TypeScript 4.0 及以上版本支持可变元组泛型,可以用它实现单个函数的类型定义,完美支持任意数量的 Loadable 参数:

type Loadable<T> = () => T;
type LoadableCombinerResult<T> = { result: T };

function useLoadableCombiner<T extends unknown[], TResult>(
  ...args: [...loadables: { [K in keyof T]: Loadable<T[K]> }, combiner: (...values: T) => TResult]
): LoadableCombinerResult<TResult> {
  // 这里是示例实现,实际需处理异步加载、错误捕获、进度跟踪等逻辑
  const loadables = args.slice(0, -1) as { [K in keyof T]: Loadable<T[K]> };
  const combiner = args[args.length - 1] as (...values: T) => TResult;
  
  // 模拟全部加载成功的情况
  const loadedValues = loadables.map(loadable => loadable()) as T;
  return { result: combiner(...loadedValues) };
}

类型逻辑说明

  • T extends unknown[]:泛型 T 用来表示所有 Loadable 返回值组成的元组类型,TypeScript 会自动推导这个元组的具体类型;
  • [...loadables: { [K in keyof T]: Loadable<T[K]> }, combiner: (...values: T) => TResult]:
    • ...loadables: { [K in keyof T]: Loadable<T[K]> }:匹配任意数量的 Loadable,每个 Loadable 的类型对应元组 T 中对应位置的元素类型;
    • combiner: (...values: T) => TResult:最后一个参数必须是一个函数,其参数列表正好是元组 T 的展开,返回值类型为 TResult;
  • 这样当你传入不同类型的 Loadable 时,TypeScript 会自动推导 T 和 TResult 的类型,combiner 函数会获得精确的参数类型提示。

示例用法

// 定义不同类型的 Loadable
const loadUser: Loadable<{ id: number; name: string }> = () => ({ id: 1, name: "Alice" });
const loadPosts: Loadable<{ id: number; title: string }[]> = () => [{ id: 101, title: "Hello World" }];
const loadSettings: Loadable<{ theme: string; darkMode: boolean }> = () => ({ theme: "light", darkMode: false });

// 使用合并函数,combiner 自动获得正确的参数类型
const combinedResult = useLoadableCombiner(
  loadUser,
  loadPosts,
  loadSettings,
  (user, posts, settings) => ({
    userName: user.name,
    totalPosts: posts.length,
    isDarkMode: settings.darkMode
  })
);

// combinedResult 的类型为 LoadableCombinerResult<{ userName: string; totalPosts: number; isDarkMode: boolean }>

内容的提问来源于stack exchange,提问作者kravemir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:45:00