Next.js, TypeScript, Prisma, Radix-UI project. So I have a loan object that looks something like this
{
"id": 25,
"borrowerName": "Test Borrower 1",
"pipelineStage": "PROSPECT",
"loanAmount": 500000,
"transactionType": "PURCHASE",
"referralSource": "Realtor Lenny",
"borrowerEmail": "test1@gmail.com",
"propertyAddress": "1234 Test Way",
"borrowerPhone": "789-546-3142",
"purchasePrice": 700000,
"creditScore": 700,
"createdAt": "2024-03-15T21:46:18.347Z",
"updatedAt": "2024-03-15T21:46:18.347Z"
}
I'm trying to build a "view single loan" page. I'm using Prisma, so createdAt and updatedAt are by default strings. Here's my code for looping over the keys and values in one go:
{Object.keys(loan || {}).map((loanKey) => {
if (loanKey === "id") return null;
if (loan && loanKey in loan) {
let value: string | number | Date | null =
loan[loanKey as keyof typeof loan];
if (loanKey === "createdAt" || loanKey === "updatedAt") {
value = new Date(value!).toLocaleString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
});
}
return (
<Card className="text-black">
<Flex direction={"column"} align={"center"}>
<Text>{formatKeyDisplay(loanKey)}: </Text>
<Card>{value}</Card>
</Flex>
</Card>
);
}
return null;
})}
I wanted to parse the createdAt and updatedAt strings out of ISO format and into something more user-friendly, so I thought to cast the value into a Date object then use .toLocaleString() to immediately cast it back into a string.
The issue with that is that I get
Type 'string | Date | null' is not assignable to type 'ReactNode'.
Type 'Date' is not assignable to type 'ReactNode'.ts(2322)
on trying to render value
presumably because TypeScript doesn't like that value becomes of type Date
even if I'm parsing it back into a string immediately.
If I try to type value
as so : let value: string | number | null = loan[loanKey as keyof typeof loan];
TypeScript will just complain that
Type 'string | number | Date | null' is not assignable to type 'string | number | null'.
Type 'Date' is not assignable to type 'string | number | null'.ts(2322)
Use a separate variable for the unprocessed value and the processed value that you know won't be a Date
:
let rawValue: string | number | Date | null =
loan[loanKey as keyof typeof loan];
let value: string | number | null;
if (loanKey === "createdAt" || loanKey === "updatedAt") {
value = new Date(rawValue!).toLocaleString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
});
} else if (rawValue instanceof Date) {
// Throw error, since the keys above are the only ones that
// show have dates
throw new Error(`Unexpected Date for field "${loanKey}"`);
} else {
// This assignment should be fine, because we weeded out `Date` above
value = rawValue;
}