如何在TypeScript中实现类型安全的Result数组unwrap函数?
实现符合TypeScript类型规则的unwrap函数
先定义基础类型,与你给出的结构一致:
type Result<T> = { status: 'success', data: T } | { status: 'failure' }; type ResultArray<T extends unknown[]> = readonly [...{ [K in keyof T]: Result<T[K]> }];
方案一:用Array.reduce实现(带精确类型)
可以给reduce的累加器指定明确类型,同时在逻辑中处理失败分支:
function unwrap<T extends unknown[]>(arr: ResultArray<T>): Result<T> { return arr.reduce<Result<T[]>>( (acc, curr) => { // 已有失败结果,直接返回 if (acc.status === 'failure') return acc; // 当前元素为失败,返回失败状态 if (curr.status === 'failure') return { status: 'failure' }; // 成功则合并数据 return { status: 'success', data: [...acc.data, curr.data] }; }, // 初始值:空数组对应的成功状态 { status: 'success', data: [] } ) as Result<T>; }
类型说明
- 给
reduce指定泛型Result<T[]>,明确累加器的类型范围; - 最后用
as Result<T>做类型断言——TypeScript无法自动推导数组T[]与元组T的等价关系,但我们可以确定逻辑上最终的data就是目标元组的实例。
方案二:递归实现(解决空数组基础情况)
如果你倾向于递归方式,可以调整递归逻辑,明确空数组的处理分支:
// 递归推导ResultArray的返回类型 type UnwrapResultArray<T extends readonly Result<unknown>[]> = T extends [] ? Result<[]> : T extends [Result<infer First>, ...infer Rest extends readonly Result<unknown>[]] ? UnwrapResultArray<Rest> extends Result<infer RestData> ? RestData extends never // 剩余数组存在失败,整体返回失败 ? Result<never> : First extends Result<infer F> ? F extends never // 当前元素是失败,整体返回失败 ? Result<never> : Result<[F, ...RestData]> : never : never : never; // 函数声明与实现 function unwrapRecursive<T extends readonly Result<unknown>[]>(arr: T): UnwrapResultArray<T> { if (arr.length === 0) { return { status: 'success', data: [] } as UnwrapResultArray<T>; } const first = arr[0]; if (first.status === 'failure') { return { status: 'failure' } as UnwrapResultArray<T>; } const restResult = unwrapRecursive(arr.slice(1) as any); if (restResult.status === 'failure') { return restResult as UnwrapResultArray<T>; } return { status: 'success', data: [first.data, ...restResult.data] } as UnwrapResultArray<T>; }
递归类型说明
- 基础情况:当输入为空数组
[]时,返回Result<[]>(成功状态+空数据数组); - 递归拆分:将数组拆分为第一个元素与剩余元素,只要其中任意一个是失败状态,整体结果就为失败;若全为成功,则合并数据类型为对应元组。
测试验证
两种实现都能满足你的示例需求:
全成功场景
unwrap([ { status: 'success', data: 1 }, { status: 'success', data: 'a'}, { status: 'success', data: true} ]); // 返回值:{ status: 'success', data: [1, 'a', true] } // 返回类型:Result<[number, string, boolean]>
包含失败场景
unwrap([ { status: 'failure' }, { status: 'success', data: 'a'}, { status: 'success', data: true} ]); // 返回值:{ status: 'failure' } // 返回类型:Result<never>(等价于失败状态)
内容的提问来源于stack exchange,提问作者Anthony S.
相关产品推荐
相关产品推荐

