I defined BodyProps
type in Table.Body
component where I know for now that I will receive two interfaces of data - Cabin
and CabinReservation
. I defined in BodyProps
, data
as a union of those two interfaces as I assumed it would guarantee safety and as the Compound component is highly reusable it will accept those two interfaces in different situations without any problems. Now in the BookingTable
when I'm passing into render
prop pattern how I would display the passed data using BookingRow
component where inside of it I defined its BookingRowProps
type interface where booking
is assigned to CabinReservation
as I will only use this data here, it spits error in previously mentioned render
that passed booking
prop is Type 'CabinReservation | Cabin' is not assignable to type 'CabinReservation'.
. Do I need to also define a union in BookingRow
to pass the issue or is there a different, better approach? I still learning best practices in defining types with TypeScript so every piece of advice will be appreciated.
Type 'Cabin | CabinReservation' is not assignable to type 'CabinReservation'.
Type 'Cabin' is missing the following properties from type 'CabinReservation': startDate, endDate, numNights, numGuests, and 4 more.ts(2322)
BookingRow component
type BookingRowProps = {
booking: CabinReservation;
};
function BookingRow({
booking: {
id: bookingId,
created_at,
startDate,
endDate,
numNights,
numGuests,
totalPrice,
status,
guests: { fullName: guestName, email },
cabins: { name: cabinName },
},
}: BookingRowProps) {
const statusToTagName = {
unconfirmed: 'blue',
'checked-in': 'green',
'checked-out': 'silver',
};
return (
<Table.Row>
<Cabin>{cabinName}</Cabin>
<Stacked>
<span>{guestName}</span>
<span>{email}</span>
</Stacked>
<Stacked>
<span>
{isToday(new Date(startDate))
? 'Today'
: formatDistanceFromNow(startDate)}{' '}
→ {numNights} night stay
</span>
<span>
{format(new Date(startDate), 'MMM dd yyyy')} —{' '}
{format(new Date(endDate), 'MMM dd yyyy')}
</span>
</Stacked>
<Tag type={statusToTagName[status]}>{status.replace('-', ' ')}</Tag>
<Amount>{formatCurrency(totalPrice)}</Amount>
</Table.Row>
);
}
export default BookingRow;
BookingTable component
function BookingTable() {
const { bookings, isLoading } = useBookings();
if (isLoading) return <Spinner />;
if (bookings.length === 0) return <Empty resourceName="bookings" />;
return (
<Menus>
<Table columns="0.6fr 2fr 2.4fr 1.4fr 1fr 3.2rem">
<Table.Header>
<div>Cabin</div>
<div>Guest</div>
<div>Dates</div>
<div>Status</div>
<div>Amount</div>
<div></div>
</Table.Header>
<Table.Body
data={bookings}
render={booking => <BookingRow key={booking.id} booking={booking} />}
/>
</Table>
</Menus>
);
}
Table Compound component
type StyledCommonRow = {
columns: string | null;
};
type TableProps = {
columns: string;
children: React.ReactNode;
};
type HeaderProps = {
children: React.ReactNode;
};
type RowProps = {
children: React.ReactNode;
};
type BodyProps = {
data: Cabin[] | CabinReservation[];
render: (data: Cabin | CabinReservation) => React.ReactNode;
};
export default function Table({ columns, children }: TableProps) {
return (
<TableContext.Provider value=>
<StyledTable role="table">{children}</StyledTable>
</TableContext.Provider>
);
}
function Header({ children }: HeaderProps) {
const { columns } = useTableContext();
return (
<StyledHeader role="row" columns={columns} as="header">
{children}
</StyledHeader>
);
}
function Row({ children }: RowProps) {
const { columns } = useTableContext();
return (
<StyledRow role="row" columns={columns}>
{children}
</StyledRow>
);
}
function Body({ data, render }: BodyProps) {
return <StyledBody>{data.map(render)}</StyledBody>;
}
Aucun commentaire:
Enregistrer un commentaire