Skip to content

Commit acc27f0

Browse files
Faithfinderclaude
andcommitted
fix: add variance annotations to fix file-order-dependent type errors
Add `in out` (invariant) variance annotations to `TData` and `TValue` type parameters on all mutually recursive types in the ColumnDef/Column cycle (ColumnDefBase, Column, Cell, Header, CoreColumn, CoreCell, CoreHeader, HeaderContext, CellContext, GroupingColumnDef, and related ColumnDef variants). This works around a known TypeScript variance computation bug (microsoft/TypeScript#44572) where file processing order causes tsc to incorrectly cache TValue as [independent], silently making ColumnDef<Row, string> assignable to ColumnDef<Row, unknown>. Also makes TableFeature's createCell/createColumn/createHeader methods generic over TValue (instead of hardcoding unknown) so that the invariant TValue flows through correctly in implementation code. Fixes #6167 Related: #4241, #4382 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e172109 commit acc27f0

File tree

9 files changed

+46
-38
lines changed

9 files changed

+46
-38
lines changed

packages/table-core/src/core/cell.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { RowData, Cell, Column, Row, Table } from '../types'
22
import { Getter, getMemoOptions, memo } from '../utils'
33

4-
export interface CellContext<TData extends RowData, TValue> {
4+
export interface CellContext<in out TData extends RowData, in out TValue> {
55
cell: Cell<TData, TValue>
66
column: Column<TData, TValue>
77
getValue: Getter<TValue>
@@ -10,7 +10,7 @@ export interface CellContext<TData extends RowData, TValue> {
1010
table: Table<TData>
1111
}
1212

13-
export interface CoreCell<TData extends RowData, TValue> {
13+
export interface CoreCell<in out TData extends RowData, in out TValue> {
1414
/**
1515
* The associated Column object for the cell.
1616
* @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#column)

packages/table-core/src/core/column.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from '../types'
99
import { getMemoOptions, memo } from '../utils'
1010

11-
export interface CoreColumn<TData extends RowData, TValue> {
11+
export interface CoreColumn<in out TData extends RowData, in out TValue> {
1212
/**
1313
* The resolved accessor function to use when extracting the value for the column from each row. Will only be defined if the column def has a valid accessor key or function defined.
1414
* @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#accessorfn)

packages/table-core/src/core/headers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface CoreHeaderGroup<TData extends RowData> {
1616
id: string
1717
}
1818

19-
export interface HeaderContext<TData, TValue> {
19+
export interface HeaderContext<in out TData, in out TValue> {
2020
/**
2121
* An instance of a column.
2222
*/
@@ -31,7 +31,7 @@ export interface HeaderContext<TData, TValue> {
3131
table: Table<TData>
3232
}
3333

34-
export interface CoreHeader<TData extends RowData, TValue> {
34+
export interface CoreHeader<in out TData extends RowData, in out TValue> {
3535
/**
3636
* The col-span for the header.
3737
* @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#colspan)

packages/table-core/src/features/ColumnFaceting.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ export interface FacetedOptions<TData extends RowData> {
4646
//
4747

4848
export const ColumnFaceting: TableFeature = {
49-
createColumn: <TData extends RowData>(
50-
column: Column<TData, unknown>,
49+
createColumn: <TData extends RowData, TValue>(
50+
column: Column<TData, TValue>,
5151
table: Table<TData>,
5252
): void => {
5353
column._getFacetedRowModel =

packages/table-core/src/features/ColumnFiltering.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ export const ColumnFiltering: TableFeature = {
265265
} as ColumnFiltersOptions<TData>
266266
},
267267

268-
createColumn: <TData extends RowData>(
269-
column: Column<TData, unknown>,
268+
createColumn: <TData extends RowData, TValue>(
269+
column: Column<TData, TValue>,
270270
table: Table<TData>,
271271
): void => {
272272
column.getAutoFilterFn = () => {
@@ -334,7 +334,7 @@ export const ColumnFiltering: TableFeature = {
334334

335335
//
336336
if (
337-
shouldAutoRemoveFilter(filterFn as FilterFn<TData>, newFilter, column)
337+
shouldAutoRemoveFilter(filterFn as FilterFn<TData>, newFilter, column as Column<TData, unknown>)
338338
) {
339339
return old?.filter((d) => d.id !== column.id) ?? []
340340
}

packages/table-core/src/features/ColumnGrouping.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export type AggregationFnOption<TData extends RowData> =
3434
| BuiltInAggregationFn
3535
| AggregationFn<TData>
3636

37-
export interface GroupingColumnDef<TData extends RowData, TValue> {
37+
export interface GroupingColumnDef<in out TData extends RowData, in out TValue> {
3838
/**
3939
* The cell to display each row for the column if the cell is an aggregate. If a function is passed, it will be passed a props object with the context of the cell and should return the property type for your adapter (the exact type depends on the adapter being used).
4040
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#aggregatedcell)

packages/table-core/src/features/ColumnOrdering.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ export const ColumnOrdering: TableFeature = {
8888
}
8989
},
9090

91-
createColumn: <TData extends RowData>(
92-
column: Column<TData, unknown>,
91+
createColumn: <TData extends RowData, TValue>(
92+
column: Column<TData, TValue>,
9393
table: Table<TData>,
9494
): void => {
9595
column.getIndex = memo(

packages/table-core/src/features/GlobalFiltering.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,16 @@ export const GlobalFiltering: TableFeature = {
118118
} as GlobalFilterOptions<TData>
119119
},
120120

121-
createColumn: <TData extends RowData>(
122-
column: Column<TData, unknown>,
121+
createColumn: <TData extends RowData, TValue>(
122+
column: Column<TData, TValue>,
123123
table: Table<TData>,
124124
): void => {
125125
column.getCanGlobalFilter = () => {
126126
return (
127127
(column.columnDef.enableGlobalFilter ?? true) &&
128128
(table.options.enableGlobalFilter ?? true) &&
129129
(table.options.enableFilters ?? true) &&
130-
(table.options.getColumnCanGlobalFilter?.(column) ?? true) &&
130+
(table.options.getColumnCanGlobalFilter?.(column as Column<TData, unknown>) ?? true) &&
131131
!!column.accessorFn
132132
)
133133
}

packages/table-core/src/types.ts

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,20 @@ import { CellContext, CoreCell } from './core/cell'
9898
import { CoreColumn } from './core/column'
9999

100100
export interface TableFeature<TData extends RowData = any> {
101-
createCell?: (
102-
cell: Cell<TData, unknown>,
103-
column: Column<TData>,
101+
createCell?: <TValue>(
102+
cell: Cell<TData, TValue>,
103+
column: Column<TData, TValue>,
104104
row: Row<TData>,
105105
table: Table<TData>,
106106
) => void
107-
createColumn?: (column: Column<TData, unknown>, table: Table<TData>) => void
108-
createHeader?: (header: Header<TData, unknown>, table: Table<TData>) => void
107+
createColumn?: <TValue>(
108+
column: Column<TData, TValue>,
109+
table: Table<TData>
110+
) => void
111+
createHeader?: <TValue>(
112+
header: Header<TData, TValue>,
113+
table: Table<TData>
114+
) => void
109115
createRow?: (row: Row<TData>, table: Table<TData>) => void
110116
createTable?: (table: Table<TData>) => void
111117
getDefaultColumnDef?: () => Partial<ColumnDef<TData, unknown>>
@@ -227,7 +233,7 @@ export interface RowModel<TData extends RowData> {
227233
rowsById: Record<string, Row<TData>>
228234
}
229235

230-
export type AccessorFn<TData extends RowData, TValue = unknown> = (
236+
export type AccessorFn<in TData extends RowData, out TValue = unknown> = (
231237
originalRow: TData,
232238
index: number,
233239
) => TValue
@@ -256,7 +262,7 @@ type ColumnIdentifiers<TData extends RowData, TValue> =
256262

257263
//
258264

259-
interface ColumnDefExtensions<TData extends RowData, TValue = unknown>
265+
interface ColumnDefExtensions<in out TData extends RowData, in out TValue = unknown>
260266
extends
261267
VisibilityColumnDef,
262268
ColumnPinningColumnDef,
@@ -267,8 +273,8 @@ interface ColumnDefExtensions<TData extends RowData, TValue = unknown>
267273
ColumnSizingColumnDef {}
268274

269275
export interface ColumnDefBase<
270-
TData extends RowData,
271-
TValue = unknown,
276+
in out TData extends RowData,
277+
in out TValue = unknown,
272278
> extends ColumnDefExtensions<TData, TValue> {
273279
getUniqueValues?: AccessorFn<TData, unknown[]>
274280
footer?: ColumnDefTemplate<HeaderContext<TData, TValue>>
@@ -279,8 +285,8 @@ export interface ColumnDefBase<
279285
//
280286

281287
export interface IdentifiedColumnDef<
282-
TData extends RowData,
283-
TValue = unknown,
288+
in out TData extends RowData,
289+
in out TValue = unknown,
284290
> extends ColumnDefBase<TData, TValue> {
285291
id?: string
286292
header?: StringOrTemplateHeader<TData, TValue>
@@ -292,8 +298,8 @@ export type DisplayColumnDef<
292298
> = ColumnDefBase<TData, TValue> & ColumnIdentifiers<TData, TValue>
293299

294300
interface GroupColumnDefBase<
295-
TData extends RowData,
296-
TValue = unknown,
301+
in out TData extends RowData,
302+
in out TValue = unknown,
297303
> extends ColumnDefBase<TData, TValue> {
298304
columns?: ColumnDef<TData, any>[]
299305
}
@@ -304,8 +310,8 @@ export type GroupColumnDef<
304310
> = GroupColumnDefBase<TData, TValue> & ColumnIdentifiers<TData, TValue>
305311

306312
export interface AccessorFnColumnDefBase<
307-
TData extends RowData,
308-
TValue = unknown,
313+
in out TData extends RowData,
314+
in out TValue = unknown,
309315
> extends ColumnDefBase<TData, TValue> {
310316
accessorFn: AccessorFn<TData, TValue>
311317
}
@@ -316,8 +322,8 @@ export type AccessorFnColumnDef<
316322
> = AccessorFnColumnDefBase<TData, TValue> & ColumnIdentifiers<TData, TValue>
317323

318324
export interface AccessorKeyColumnDefBase<
319-
TData extends RowData,
320-
TValue = unknown,
325+
in out TData extends RowData,
326+
in out TValue = unknown,
321327
> extends ColumnDefBase<TData, TValue> {
322328
id?: string
323329
accessorKey: (string & {}) | keyof TData
@@ -347,7 +353,7 @@ export type ColumnDefResolved<
347353
accessorKey?: string
348354
}
349355

350-
export interface Column<TData extends RowData, TValue = unknown>
356+
export interface Column<in out TData extends RowData, in out TValue = unknown>
351357
extends
352358
CoreColumn<TData, TValue>,
353359
ColumnVisibilityColumn,
@@ -360,11 +366,13 @@ export interface Column<TData extends RowData, TValue = unknown>
360366
ColumnSizingColumn,
361367
ColumnOrderColumn {}
362368

363-
export interface Cell<TData extends RowData, TValue>
364-
extends CoreCell<TData, TValue>, GroupingCell {}
369+
export interface Cell<in out TData extends RowData, in out TValue>
370+
extends CoreCell<TData, TValue>,
371+
GroupingCell {}
365372

366-
export interface Header<TData extends RowData, TValue>
367-
extends CoreHeader<TData, TValue>, ColumnSizingHeader {}
373+
export interface Header<in out TData extends RowData, in out TValue>
374+
extends CoreHeader<TData, TValue>,
375+
ColumnSizingHeader {}
368376

369377
export interface HeaderGroup<
370378
TData extends RowData,

0 commit comments

Comments
 (0)