Reputation: 2402
I'm trying to make a typescript function with a conditional return type.
My function need to accept 2 types : BotLotteryPrize[]
and Lot[]
and return BotLotteryPrize
or Lot
accordingly.
BotLotteryPrize:
export type BotLotteryPrize = {
id: string
videoUrl: string | null
probabilityToWin: number
...
}
Lot:
export type Lot = {
id: string
probabilityToWin: number
credit: number | null
...
}
So I tried to write that :
type BotLotteryPrizeOrLot<T extends (BotLotteryPrize | Lot)[]> =
T extends BotLotteryPrize[] ? BotLotteryPrize : Lot;
function raffleDrawWithDistribution<T extends Array<BotLotteryPrize | Lot>>(
items: T,
): BotLotteryPrizeOrLot<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: Lot | BotLotteryPrize = null;
items.forEach((item, idx) => {
if (randomInt > probabilities[idx] && randomInt <= probabilities[idx + 1]) {
wonItem = item;
}
});
return wonItem;
}
At the return of my function I get a ts error :
Type 'BotLotteryPrize | Lot' is not assignable to type 'BotLotteryPrizeOrLot<T>'.
Type 'BotLotteryPrize' is not assignable to type 'BotLotteryPrizeOrLot<T>
Upvotes: 0
Views: 32
Reputation: 187034
First of all this type:
type BotLotteryPrizeOrLot<T extends (BotLotteryPrize | Lot)[]> =
T extends BotLotteryPrize[] ? BotLotteryPrize : Lot;
Is kind of silly. It basically simplifies to:
type BotLotteryPrizeOrLot<T extends (BotLotteryPrize | Lot)[]> = T[number]
And conditional types are notoriously difficult to assign to so this is a big improvement. It's also so simple you don't need it at all.
I say, change your function to this:
function raffleDrawWithDistribution<T extends BotLotteryPrize | Lot>(
items: T[],
): T {
//...
}
And then just let items
infer the type for you. Calling items.find
will return a T | undefined
so you don't have to mess with it.
const wonItem = items.find((item, idx) => {
return randomInt > probabilities[idx] && randomInt <= probabilities[idx + 1]
})
if (!wonItem) throw new Error("Failed to win an item!")
return wonItem;
Upvotes: 2