如何在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
相关产品推荐
相关产品推荐

