I have this function with a switch case that returns two different results based on the case.
export function getTimeAgo(
date: Date | string,
mode: "days" | "minutes" = "days"
) {
if (typeof date === "string") {
date = new Date(date);
}
switch (mode) {
case "days":
return getTimeAgoByDays(date);
case "minutes":
return getTimeAgoByMinutes(date);
default:
return { timeAgo: "", numFormat: null };
}
}
The getTimeAgoByDays
function:
function getTimeAgoByDays(date: Date) {
let timeAgo = "";
const curDate = new Date();
const days = Math.round(
(date.valueOf() - curDate.valueOf()) / (1000 * 60 * 60 * 24)
);
if (days === 0) {
timeAgo = "Ends today";
} else if (days < 0) {
const nonNegativeDays = days * -1;
timeAgo = `${nonNegativeDays} days behind`;
} else {
timeAgo = `${days} days left`;
}
if (days === 1) {
timeAgo = timeAgo.replace("days", "day");
}
return { timeAgo, numFormat: days };
}
Then calling it to get the results:
const { timeAgo, numFormat: days } = getTimeAgo(date,"days");
In the days
variable I get an error stating that it could be null
. But based on the mode
, days
, shouldn't the result always be non-null
?
CodePudding user response:
TypyScript does not do any control flow analysis to determine the return type of a function based on the input values and the code inside the function. When you hover over the definiton of getTimeAgo
, you will see that the return type is just a union of all the different things the function returned.
{
timeAgo: string;
numFormat: number;
} | {
timeAgo: string;
numFormat: null;
}
So no matter what you pass to the function, the return type will always be this union where numFormat
could be null
.
You can change this behaviour with function overloading. Here you explicitly tell TypeScript what the return type will be based on the arguments.
export function getTimeAgo<
T extends "days" | "minutes"
>(date: Date | string, mode: T): {
timeAgo: string, numFormat: T extends "days" | "minutes" ? number : null
}
export function getTimeAgo(
date: Date | string,
mode: "days" | "minutes" = "days"
) {
/* ... */
}
In the return type we can create conditions based on T
and form a fitting return type accordingly.
But in the code you provided this does not seem to be necessary. You could also just remove the default
clause of the switch statement, since it is not reachable.