I've been learning how to use react and typescript recently and am currently trying to use Tanstack Table to define a complicated table using generic types for reusability. I'm running into type errors with how I am trying to spread my custom function for cell definition.
The error:
Argument of type '{ getUniqueValues?: AccessorFn<BulkEditRow, unknown[]> | undefined; footer?: ColumnDefTemplate<HeaderContext<BulkEditRow, unknown>> | undefined; ... 22 more ...; id: string; } | ... 6 more ... | { ...; }' is not assignable to parameter of type 'IdentifiedColumnDef<BulkEditRow, number | null>'. Type '{ getUniqueValues?: AccessorFn<BulkEditRow, unknown[]> | undefined; footer?: ColumnDefTemplate<HeaderContext<BulkEditRow, unknown>> | undefined; ... 22 more ...; id: string; }' is not assignable to type 'IdentifiedColumnDef<BulkEditRow, number | null>'. Types of property 'cell' are incompatible. Type 'ColumnDefTemplate<CellContext<BulkEditRow, unknown>> | undefined' is not assignable to type 'ColumnDefTemplate<CellContext<BulkEditRow, number | null>> | undefined'. Type '(props: CellContext<BulkEditRow, unknown>) => any' is not assignable to type 'ColumnDefTemplate<CellContext<BulkEditRow, number | null>> | undefined'. Type '(props: CellContext<BulkEditRow, unknown>) => any' is not assignable to type '(props: CellContext<BulkEditRow, number | null>) => any'. Types of parameters 'props' and 'props' are incompatible. Type 'CellContext<BulkEditRow, number | null>' is not assignable to type 'CellContext<BulkEditRow, unknown>'. The types of 'cell.column.columnDef' are incompatible between these types. Type 'ColumnDef<BulkEditRow, number | null>' is not assignable to type 'ColumnDef<BulkEditRow, unknown>'. Type 'ColumnDefBase<BulkEditRow, number | null> & StringHeaderIdentifier' is not assignable to type 'ColumnDef<BulkEditRow, unknown>'. Type 'ColumnDefBase<BulkEditRow, number | null> & StringHeaderIdentifier' is not assignable to type 'AccessorFnColumnDefBase<BulkEditRow, unknown> & IdIdentifier<BulkEditRow, unknown>'. Property 'accessorFn' is missing in type 'ColumnDefBase<BulkEditRow, number | null> & StringHeaderIdentifier' but required in type 'AccessorFnColumnDefBase<BulkEditRow, unknown>'.ts(2345) types.d.ts(83, 5): 'accessorFn' is declared here. (property) IdentifiedColumnDef<BulkEditRow, number | null>.header?: ColumnDefTemplate<HeaderContext<BulkEditRow, number | null>> | undefined
I pass to a function that determines what should be returned
export const useEditableCell = <TData extends object>(
setTableState: React.Dispatch<React.SetStateAction<TableState>>,
getTableState: TableState,
customUpdateFunction?: CustomUpdateFunction,
mode: 'View' | 'Edit' = 'Edit'
) => {
const editableColumn = useMemo<Partial<ColumnDef<TData>>>(() => {
return {
cell: (cellProps) => {
const isCurrentErrorCell =
getTableState.errorLocation &&
cellProps.row.index === getTableState.errorLocation.rowIndex &&
cellProps.column.id === getTableState.errorLocation.columnId
const cellValue = cellProps.getValue()
const displayValue = cellValue === null ? '' : String(cellValue)
if (
(getTableState.message != null && !isCurrentErrorCell) ||
mode === 'View'
) {
return <TableDisplayCell value={displayValue} />
}
return (
<EditableCell
{...(cellProps as unknown as Cell<TData, unknown>)}
updateData={
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
customUpdateFunction ?? cellProps.table.options.meta!.updateData
}
setTableState={setTableState}
/>
)
},
}
}, [
getTableState.errorLocation,
getTableState.message,
mode,
customUpdateFunction,
setTableState,
])
return editableColumn
}
This then returns either a cell that is editable using mui textfield or div with a display value inside.
Here is how the useEditableCell is used:
const editableCell = useEditableCell<BulkEditRow>(
setTableState,
getTableState
)
And then used inside the column definitions here:
columnHelper.accessor('percentAustralia', {
id: 'percentAustralia',
header: () => RenderDefaultHeaderCell('% Australia'),
size: 12,
meta: {
validate: validatePercentageValueInTable,
},
...editableCell,
}),
I'm just very confused on why this doesn't work when if I were to simply define the column like so:
cell: (cellProps) => {
<EditableCell
{...(cellProps as unknown as Cell<TData, unknown>)}
updateData={
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
cellProps.table.options.meta!.updateData
}
setTableState={setTableState}
/>
}
It works fine. Any help would be appreciated, though everything I am doing is done with a purpose and a specific use case in mind, so I cannot change anything that I am doing.