TypeScript条件返回类型函数报错:返回值类型不匹配求助
解决TypeScript条件返回类型不匹配问题
问题分析
你当前的条件类型BotLotteryPrizeOrLot<T>逻辑上成立,但TypeScript无法在函数内部跟踪wonItem的类型与泛型T的关联——forEach循环会抹平类型细节,TS只能识别wonItem为BotLotteryPrize | Lot,无法确认它恰好匹配BotLotteryPrizeOrLot<T>的约束,因此抛出类型不匹配错误。
解决方案一:调整泛型约束,简化类型推断
直接将泛型约束在单个奖品类型上,让TS自动根据输入数组的类型推导返回值类型,无需额外条件类型:
function raffleDrawWithDistribution<T extends BotLotteryPrize | Lot>( items: T[], ): T { const randomInt = this.generateRandomInt(); const sumOfProbabilities = items.reduce( (acc, currentItem) => acc + currentItem.probabilityToWin, 0, ); if (sumOfProbabilities !== 1) { items.forEach((item) => { item.probabilityToWin = item.probabilityToWin / sumOfProbabilities; }); } const probabilities = items.reduce( (acc, currentLot, idx) => { const nextProbability = acc[idx] + currentLot.probabilityToWin; return [...acc, nextProbability]; }, [0], ); let wonItem: T | null = null; items.forEach((item, idx) => { if (randomInt > probabilities[idx] && randomInt <= probabilities[idx + 1]) { wonItem = item; } }); // 处理空数组的边界情况,确保运行时安全 if (!wonItem) { throw new Error("No items provided for raffle draw"); } return wonItem; }
优势
- 泛型
T直接绑定输入数组的元素类型,TS能清晰推断返回值为T,避免类型歧义。 - 内部
wonItem的类型与输入元素完全匹配,赋值时不会出现类型冲突。 - 新增空数组判断,同时保证运行时安全与类型正确性。
解决方案二:用函数重载严格约束输入输出
如果需要严格禁止传入混合BotLotteryPrize和Lot的数组,可以通过函数重载明确合法的输入输出组合:
// 重载声明:明确两种合法的输入输出配对 function raffleDrawWithDistribution(items: BotLotteryPrize[]): BotLotteryPrize; function raffleDrawWithDistribution(items: Lot[]): Lot; // 通用实现 function raffleDrawWithDistribution( items: (BotLotteryPrize | Lot)[] ): BotLotteryPrize | Lot { const randomInt = this.generateRandomInt(); const sumOfProbabilities = items.reduce( (acc, currentItem) => acc + currentItem.probabilityToWin, 0, ); if (sumOfProbabilities !== 1) { items.forEach((item) => { item.probabilityToWin = item.probabilityToWin / sumOfProbabilities; }); } const probabilities = items.reduce( (acc, currentLot, idx) => { const nextProbability = acc[idx] + currentLot.probabilityToWin; return [...acc, nextProbability]; }, [0], ); let wonItem: BotLotteryPrize | Lot | null = null; items.forEach((item, idx) => { if (randomInt > probabilities[idx] && randomInt <= probabilities[idx + 1]) { wonItem = item; } }); if (!wonItem) { throw new Error("No items provided for raffle draw"); } return wonItem; }
优势
- 明确禁止混合类型数组的输入,编译阶段就会拦截非法调用。
- 调用方无需手动指定泛型,TS会根据输入自动匹配对应的重载,返回正确类型。
内容的提问来源于stack exchange,提问作者Thibault Walterspieler
相关产品推荐
相关产品推荐

