Skip to content

tsc silently drops ColumnDef type errors depending on file processing order (TypeScript variance bug) #6167

@Faithfinder

Description

@Faithfinder

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions