From 3ff41332caa435adeab8504b91a18eed9a6ff687 Mon Sep 17 00:00:00 2001 From: Nirmal Shaji Joseph Date: Fri, 4 Sep 2026 23:18:52 +0530 Subject: [PATCH] fix(react-table): type aggregatedCell against bound cellComponents in createAppColumnHelper The `App*` column definition types produced by `createAppColumnHelper` enhanced only `cell`, `header`, and `footer` with the registered `cellComponents` / `headerComponents`. `aggregatedCell` (added by `rowAggregationFeature`) was left with its core type, so its render prop `cell` did not expose the bound components the way `cell` does. Add `aggregatedCell` to the omitted keys and re-declare it mirroring `cell` (it shares the cell context) in `AppColumnDefBase`, `AppDisplayColumnDef`, and `AppGroupColumnDef`. Type-only change. Fixes #6583 --- packages/react-table/src/createTableHook.tsx | 23 ++++--- .../tests/createAppColumnHelper.test-d.tsx | 60 +++++++++++++++++++ 2 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 packages/react-table/tests/createAppColumnHelper.test-d.tsx diff --git a/packages/react-table/src/createTableHook.tsx b/packages/react-table/src/createTableHook.tsx index cceefdb70a..fcb0e3d20c 100644 --- a/packages/react-table/src/createTableHook.tsx +++ b/packages/react-table/src/createTableHook.tsx @@ -97,11 +97,14 @@ export type AppColumnDefBase< THeaderComponents extends Record>, > = Omit< IdentifiedColumnDef, - 'cell' | 'header' | 'footer' + 'cell' | 'aggregatedCell' | 'header' | 'footer' > & { cell?: AppColumnDefTemplate< AppCellContext > + aggregatedCell?: AppColumnDefTemplate< + AppCellContext + > header?: AppColumnDefTemplate< AppHeaderContext > @@ -120,11 +123,14 @@ export type AppDisplayColumnDef< THeaderComponents extends Record>, > = Omit< DisplayColumnDef, - 'cell' | 'header' | 'footer' + 'cell' | 'aggregatedCell' | 'header' | 'footer' > & { cell?: AppColumnDefTemplate< AppCellContext > + aggregatedCell?: AppColumnDefTemplate< + AppCellContext + > header?: AppColumnDefTemplate< AppHeaderContext > @@ -143,11 +149,14 @@ export type AppGroupColumnDef< THeaderComponents extends Record>, > = Omit< GroupColumnDef, - 'cell' | 'header' | 'footer' | 'columns' + 'cell' | 'aggregatedCell' | 'header' | 'footer' | 'columns' > & { cell?: AppColumnDefTemplate< AppCellContext > + aggregatedCell?: AppColumnDefTemplate< + AppCellContext + > header?: AppColumnDefTemplate< AppHeaderContext > @@ -173,7 +182,7 @@ export type AppColumnHelper< > = { /** * Creates a data column definition with an accessor key or function. - * The cell, header, and footer contexts include pre-bound components. + * The cell, aggregatedCell, header, and footer contexts include pre-bound components. */ accessor: < TAccessor extends AccessorFn | DeepKeys, @@ -212,7 +221,7 @@ export type AppColumnHelper< /** * Creates a display column definition for non-data columns. - * The cell, header, and footer contexts include pre-bound components. + * The cell, aggregatedCell, header, and footer contexts include pre-bound components. */ display: ( column: AppDisplayColumnDef< @@ -225,7 +234,7 @@ export type AppColumnHelper< /** * Creates a group column definition with nested child columns. - * The cell, header, and footer contexts include pre-bound components. + * The cell, aggregatedCell, header, and footer contexts include pre-bound components. */ group: ( column: AppGroupColumnDef< @@ -725,7 +734,7 @@ export function createTableHook< /** * Create a column helper pre-bound to the features and components configured in this table hook. - * The cell, header, and footer contexts include pre-bound components (e.g., `cell.TextCell`). + * The cell, aggregatedCell, header, and footer contexts include pre-bound components (e.g., `cell.TextCell`). * @example * ```tsx * const columnHelper = createAppColumnHelper() diff --git a/packages/react-table/tests/createAppColumnHelper.test-d.tsx b/packages/react-table/tests/createAppColumnHelper.test-d.tsx new file mode 100644 index 0000000000..e8ec158c50 --- /dev/null +++ b/packages/react-table/tests/createAppColumnHelper.test-d.tsx @@ -0,0 +1,60 @@ +// Type-level tests for `createAppColumnHelper`, checked by `test:types` (tsc). +// Not executed by vitest (the `.test-d.` name is excluded from its run glob). + +import * as React from 'react' +import { rowAggregationFeature, tableFeatures } from '@tanstack/table-core' +import { test } from 'vitest' +import { createTableHook, createTableHookContexts } from '../src' + +type Person = { + id: string + name: string +} + +const features = tableFeatures({ + rowAggregationFeature, +}) +const contexts = createTableHookContexts() + +function NameCell() { + const cell = contexts.useCellContext() + + return {cell.getValue().toUpperCase()} +} + +const appTable = createTableHook({ + features, + tableContext: contexts.tableContext, + cellContext: contexts.cellContext, + headerContext: contexts.headerContext, + cellComponents: { NameCell }, +}) +const columnHelper = appTable.createAppColumnHelper() + +test('aggregatedCell is bound to cellComponents like cell', () => { + columnHelper.accessor('name', { + id: 'name', + // The bound `cellComponents` are available on the cell context here... + cell: ({ cell }) => , + // ...and must be equally available on the aggregatedCell context. + aggregatedCell: ({ cell }) => , + }) + + columnHelper.display({ + id: 'display', + cell: ({ cell }) => , + aggregatedCell: ({ cell }) => , + }) + + columnHelper.group({ + id: 'group', + aggregatedCell: ({ cell }) => , + columns: [], + }) + + columnHelper.accessor('name', { + id: 'guard', + // @ts-expect-error a component that was not registered is not bound + aggregatedCell: ({ cell }) => , + }) +})