different TypeScript types for subRows #4484
Replies: 8 comments 3 replies
-
|
Hey mate, I had issues with this but found a nice solution. Basically you need to create a new table for the inner arrays and then you can use the manual expanding option. The code below uses tailwind for css: import type { ColumnDef } from "@tanstack/react-table";
import { flexRender } from "@tanstack/react-table";
import { getCoreRowModel, getExpandedRowModel, useReactTable } from "@tanstack/react-table";
import React from "react";
type Project = {
_type: "Project";
title: string;
dueDate: Date;
tasks?: Task[];
};
type Task = {
_type: "Task";
title: string;
status: "Waiting" | "In Progress" | "Urgent" | "On Hold" | "Done";
assignee: string;
};
const ExampleTableWithSubRows: React.FC<{ projects: Project[] }> = ({ projects }) => {
const columns = React.useMemo<ColumnDef<Project>[]>(
() => [
{
header: "Title",
accessorKey: "title",
cell: ({ getValue, row }) => {
return (
<div className="flex gap-2">
{row.getCanExpand() && (
<span
className={`h-4 w-4 transition-transform ${
row.getIsExpanded() ? "rotate-90" : "rotate-0"
}`}
>
{">"}
</span>
)}{" "}
{getValue() as string}
</div>
);
},
},
{ header: "dueDate", accessorKey: "dueDate" },
],
[],
);
const headlessTable = useReactTable({
data: projects || [],
columns,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
enableExpanding: true,
getRowCanExpand: (row) => !!row.original?.tasks?.length, // check if the sub rows can expand
});
return (
<table className="w-full">
<thead>
{headlessTable.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<th
key={header.id}
className={
"whitespace-nowrap border-b border-gray-400 p-3 text-left text-xs font-semibold"
}
>
{flexRender(header.column.columnDef.header, header.getContext())}
</th>
);
})}
</tr>
))}
</thead>
<tbody className="divide-y divide-gray-200 bg-white text-xs">
{headlessTable.getRowModel().rows.map((row) => {
return (
<>
<tr
key={row.id}
{...(row.getCanExpand() && {
onClick: row.getToggleExpandedHandler(),
style: { cursor: "pointer" },
})}
>
{row.getVisibleCells().map((cell) => {
return (
<td
key={cell.id}
className={"justify-center whitespace-nowrap p-3 text-left align-middle"}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
);
})}
</tr>
{row.original.tasks && row.getIsExpanded() && (
<tr key={row.id + "expansion"}>
<td colSpan={row.getVisibleCells().length} className="px-5">
<SubTable tasks={row.original.tasks} />
</td>
</tr>
)}
</>
);
})}
</tbody>
</table>
);
};
const SubTable: React.FC<{ tasks: Task[] }> = ({ tasks }) => {
const columns = React.useMemo<ColumnDef<Task>[]>(
() => [
{ header: "Title", accessorKey: "title" },
{ header: "Assignee", accessorKey: "assignee" },
{ header: "Status", accessorKey: "status" },
{ header: "Type", accessorKey: "_type" },
],
[],
);
const headlessTable = useReactTable({
data: tasks || [],
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<table className="w-full">
<thead>
{headlessTable.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<th key={header.id} className={"whitespace-nowrap p-3 text-left text-xs font-semibold"}>
{flexRender(header.column.columnDef.header, header.getContext())}
</th>
);
})}
</tr>
))}
</thead>
<tbody className="divide-y divide-gray-200 text-xs">
{headlessTable.getRowModel().rows.map((row) => {
return (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => {
return (
<td key={cell.id} className={"whitespace-nowrap p-3 text-left"}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
};
export default () => {
return (
<ExampleTableWithSubRows
projects={[
{
_type: "Project",
dueDate: new Date(),
title: "Example sub rows",
tasks: [{ _type: "Task", assignee: "Ligma", status: "In Progress", title: "TODO" }],
},
{ _type: "Project", dueDate: new Date(), title: "Example sub rows" },
]}
/>
);
};
|
Beta Was this translation helpful? Give feedback.
-
|
Is there a better solution yet? |
Beta Was this translation helpful? Give feedback.
-
|
any solution for this? |
Beta Was this translation helpful? Give feedback.
-
|
It's not a definite solution, but we can fake-cast the type to bypass the typescript error. unless you need to call getSubRows to get the |
Beta Was this translation helpful? Give feedback.
-
|
My solution so far is a union type for the table data, and then a type guard every time I access the data in columns or subRows: export type TableItem = ItemGroup | LineItem | SubItem;
const columns = useMemo<MRT_ColumnDef<TableItem>[]>(() => [
{
header: "Name",
accessorFn(row: TableItem) {
//...
if (isLineItem(row) || isItemGroup(row)) {
color = "primary";
} else {
color = "secondary";
}
//...
},
},
]);
const tableOptions = {
///...
columns,
getSubRows: (row: TableItem) => {
if (isItemGroup(row)) {
return row.lineItems || undefined;
}
if (isLineItem(row)) {
return row.subItems || undefined;
}
if (isSubItem(row)) {
return undefined;
}
},
//...
};
|
Beta Was this translation helpful? Give feedback.
-
|
I'm using the shadcn/ui table example. And I've solved the problem by using the "any" option: The code of the table: interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
pathSubRows?: string;
}
export function DataTable<TData, TValue>({
columns,
data,
pathSubRows,
}: DataTableProps<TData, TValue>) {
const [expanded, setExpanded] = useState<ExpandedState>({});
const table = useReactTable({
data,
columns,
state: {
expanded,
},
getCoreRowModel: getCoreRowModel(),
onExpandedChange: setExpanded,
getSubRows: pathSubRows ? (row: any) => row[pathSubRows] : undefined,
getExpandedRowModel: getExpandedRowModel(),
});
//....What's it called: <DataTable columns={columns}
data={userOrders}
pathSubRows="tasks"
/> |
Beta Was this translation helpful? Give feedback.
-
|
Is there a better solution yet? |
Beta Was this translation helpful? Give feedback.
-
|
This is a sorely needed feature. I have a data model where customers can have various orders. This results in the following data type: type Customer = {
customer_name: string;
customer_address: string;
customer_status: string;
orders: Order[]
};
type Order = {
order_number: number;
order_date: Date;
order_total: number;
order_paid: string;
}This means that I have nested sub-rows with a different type than the main row. The expanding docs says:
Instead of a custom expanding UI that is rendered below the main row, I'd like to have nested sub-rows that expand into their own columns. This is something that is doable with Excel's pivot table feature.
Right now, there's not an easy way to accomplish this. One option is to either the customer and order information and treat it as a normal row. However, this causes the customer information to be filled in for every row. type CombinedData = Omit<Data, "orders"> & Partial<Order>;
const data: Customer[] = [];
const combinedData: CombinedData = [];
for (const row of data) {
const { orders, ...rest } = row;
if (!row.orders.length) {
combinedData.push(rest);
continue;
}
for (const order of orders) {
combinedData.push({ ...rest, ...order });
}
}This works fine, but the customer data is displayed repeatedly for every row. The alternative is to use const columns = [
columnHelper.accessor("customer_name", {
header: "Customer Name",
}),
columnHelper.accessor("customer_address", {
header: "Customer Address",
}),
// Type error because "order_number" does not exist (regular nested data can be accessed with "orders.order_number",
// but that doesn't work because orders is an array)
// Argument of type "order_number" is not assignable to parameter of type: ...
columnHelper.accessor("order_number", {
header: "Order Number",
}),
];
const table = useReactTable<Customer>({
data,
// Type error because row.orders is not of type Customer
// Type ... is missing the following properties from type ...
getSubRows: (row) => row.orders,
}); |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
How can I declare a different Data type for subRows ? All the examples I have seen use the same type for nested subrows.
In my case I have Projects (parent) which have 1 or more Tasks (children aka subRows).
and my data type is
Project[]When i declare the React Table using Project as the generic type ...
... I get a TypeScript error when defining
getSubRows:Beta Was this translation helpful? Give feedback.
All reactions