Description
tsc silently accepts incorrect type assignments involving ColumnDef<TData, TValue> that the IDE (VS Code / language server) correctly flags as errors. The root cause is a known TypeScript variance computation bug with mutually recursive generic types (microsoft/TypeScript#44572).
The ColumnDef and Column types are mutually recursive, and when TypeScript's variance computation hits the cycle, it bails out and caches TValue as [independent] — making ColumnDef<Row, string> incorrectly assignable to ColumnDef<Row, unknown>. Whether this happens depends on file processing order (alphabetical glob expansion).
Reproduction
Repo: https://github.com/Faithfinder/ts-ide-cli-repro (main branch uses @tanstack/react-table, standalone branch is zero-dependency)
git clone https://github.com/Faithfinder/ts-ide-cli-repro.git
cd ts-ide-cli-repro
pnpm install
npx tsc --noEmit # Exit code 0 — errors silently dropped (BUG)
Rename the trigger file so it sorts after test.ts:
mv src/_trigger.ts src/zzz_trigger.ts
npx tsc --noEmit # Exit code 1 — errors correctly reported
The test file contains assignments that should always error:
import type { ColumnDef } from "@tanstack/react-table";
type Row = { name: string; age: number };
declare function useTable(columns: ColumnDef<Row>[]): void;
declare const columnsUnion: (ColumnDef<Row, string> | ColumnDef<Row, number>)[];
useTable(columnsUnion); // Should error — IDE flags it, tsc doesn't
declare const columnsString: ColumnDef<Row, string>[];
useTable(columnsString); // Should error — IDE flags it, tsc doesn't
The trigger file just imports Column in a way that causes the variance cycle to be computed before test.ts is processed:
import type { RowData, Column } from "@tanstack/react-table";
export const f = <TData extends RowData>(cols: Column<TData, unknown>[]) => {
cols.map((col) => col.id);
};
Root cause
This is TypeScript's variance computation cycle-handling bug: microsoft/TypeScript#44572 (closed as Design Limitation). A fix was attempted in microsoft/TypeScript#48080 but rejected due to performance regression.
The --generateTrace output shows getVariancesWorker computing different variance results for ColumnDefBase's TValue depending on file order.
Suggested fix
TypeScript 4.7 introduced variance annotations (in/out/in out) specifically as the workaround for this class of bugs (microsoft/TypeScript#48240). Adding explicit variance annotations to ColumnDef, Column, and related mutually recursive types would establish correct variance regardless of file processing order.
This would also resolve the long-standing confusion in #4241 and #4382, where Tanner couldn't reproduce the ColumnDef type errors locally (likely due to different file ordering in different projects).
Related issues
Versions
@tanstack/react-table: 8.20.6
- TypeScript: 5.9.3
Description
tscsilently accepts incorrect type assignments involvingColumnDef<TData, TValue>that the IDE (VS Code / language server) correctly flags as errors. The root cause is a known TypeScript variance computation bug with mutually recursive generic types (microsoft/TypeScript#44572).The
ColumnDefandColumntypes are mutually recursive, and when TypeScript's variance computation hits the cycle, it bails out and cachesTValueas[independent]— makingColumnDef<Row, string>incorrectly assignable toColumnDef<Row, unknown>. Whether this happens depends on file processing order (alphabetical glob expansion).Reproduction
Repo: https://github.com/Faithfinder/ts-ide-cli-repro (
mainbranch uses@tanstack/react-table,standalonebranch is zero-dependency)Rename the trigger file so it sorts after
test.ts:mv src/_trigger.ts src/zzz_trigger.ts npx tsc --noEmit # Exit code 1 — errors correctly reportedThe test file contains assignments that should always error:
The trigger file just imports
Columnin a way that causes the variance cycle to be computed beforetest.tsis processed:Root cause
This is TypeScript's variance computation cycle-handling bug: microsoft/TypeScript#44572 (closed as Design Limitation). A fix was attempted in microsoft/TypeScript#48080 but rejected due to performance regression.
The
--generateTraceoutput showsgetVariancesWorkercomputing different variance results forColumnDefBase'sTValuedepending on file order.Suggested fix
TypeScript 4.7 introduced variance annotations (
in/out/in out) specifically as the workaround for this class of bugs (microsoft/TypeScript#48240). Adding explicit variance annotations toColumnDef,Column, and related mutually recursive types would establish correct variance regardless of file processing order.This would also resolve the long-standing confusion in #4241 and #4382, where Tanner couldn't reproduce the
ColumnDeftype errors locally (likely due to different file ordering in different projects).Related issues
Versions
@tanstack/react-table: 8.20.6