Skip to content

Dedupe identical object literal types before subtype reduction - #64729

Open
Camille Barneaud (gadcam) wants to merge 2 commits into
microsoft:mainfrom
gadcam:perf/dedupe-identical-object-literals-in-subtype-reduction
Open

Camille Barneaud (gadcam) wants to merge 2 commits into
microsoft:mainfrom
gadcam:perf/dedupe-identical-object-literals-in-subtype-reduction

Conversation

@gadcam

@gadcam Camille Barneaud (gadcam) commented Oct 10, 2026 •

Copy link
Copy Markdown

Fixes #48364: this fixes the checker blow-up on large JSON arrays. Editor responsiveness on very large JSON files may still warrant .d.json.ts.

removeSubtypes relates every pair of union constituents. Array literals of records, typically from resolveJsonModule imports, produce one object literal type per element, so their element type costs O(n²) structural checks, and the relation cache grows with them.

This removes object literal types that are identical to an earlier constituent before the pairwise loop. Identical types are mutual subtypes, so the loop would keep only the first anyway and the reduced type is the same. One visible difference: array literals with many records of one shape followed by another shape (e.g. 1,000 × { a: "" } + 100 × { a: 0 }) no longer hit the subtype reduction limit and report a false TS2590. Two types count as identical when they have the same hash of their object flags and properties (names, flags, check flags and types), like the other CacheHashKey-keyed caches in the checker. Members and property types are only read when they are already resolved (valueSymbolLinks.resolvedType, no accessors, methods, or deferred/instantiated/mapped properties), so the check never triggers type resolution and can't change circularity behavior (see #46981).

Results

colornerd.json from #48364 (29,177 objects, 3 shapes):

before after
check did not finish (>12 min, >4.5 GB RSS) 0.06s

The blow-up starts between 23K and 24K elements. Below that, the same file checks in ~0.1s.

Interleaved A/B runs (Mann-Whitney U on wall time):

project wall p
vscode @ 9cf0128 +0.37% 0.85
typescript-benchmarking Compiler 0% —
typescript-benchmarking Compiler-Unions −3.45% (check −0.42%) 0.029
app with 5 JSON imports (807-object file with 113 shapes) −12.3% (check −16.5%) <0.001

Type and symbol counts are identical in every run. Declaration emit for the JSON imports is identical.

Tests

arrayLiteralIdenticalObjectLiteralsSubtypeReduction.ts covers JSON records with reordered keys, mixed property types and null, plus the cases the shape key must handle or skip: reordered keys, optional properties, spreads, methods, accessors and as const. Its baselines are byte-identical with and without the checker change, and a temporary trace confirmed the new path runs for most of these cases.

arrayLiteralManyObjectLiteralsNotTooComplex.ts reports TS2590 without this change and no error with it.

AI disclosure

This change was written with Claude Code (investigation, patch, test, and benchmarks). I have reviewed it, understand it, and will handle review feedback myself.

removeSubtypes compares every pair of constituents, which makes array
literals with many records quadratic. Large JSON imports hit this hard:
the colornerd.json file from microsoft#48364 (29K objects) never finishes, using
gigabytes for the relation cache.

Object literal types whose properties have the same names, flags and
already-resolved types are identical, so the pairwise loop would keep
only the first of them anyway. Remove them up front, keyed by a hash of
their shape. Property types are only read when already resolved, so the
new check never triggers type resolution.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 10, 2026 18:01
@typescript-automation typescript-automation Bot added For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Oct 10, 2026
@typescript-automation

Copy link
Copy Markdown
Contributor

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@typescript-automation typescript-automation Bot added For Milestone Bug PRs that fix a bug with a specific milestone and removed For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Oct 10, 2026
@gadcam

Copy link
Copy Markdown
Author

TypeScript Bot (@typescript-bot) It fixes issue #48364

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Shape-key computation can trigger member resolution and the test does not detect regression of the optimization.

2 open findings
What changed in this PR

Optimizes subtype reduction by deduplicating structurally identical object literal types before pairwise comparison.

Changes:

  • Adds object-literal shape hashing and deduplication.
  • Adds compiler coverage and generated baselines for JSON and object-literal cases.
File Description
tsc/​internal/​checker/​checker.go Implements shape-based deduplication.
tsc/​testdata/​tests/​cases/​compiler/​arrayLiteralIdenticalObjectLiteralsSubtypeReduction.ts Adds compiler scenarios.
tsc/​testdata/​baselines/​reference/​compiler/​arrayLiteralIdenticalObjectLiteralsSubtypeReduction.types Records inferred types.
tsc/​testdata/​baselines/​reference/​compiler/​arrayLiteralIdenticalObjectLiteralsSubtypeReduction.symbols Records resolved symbols.
tsc/​testdata/​baselines/​reference/​compiler/​arrayLiteralIdenticalObjectLiteralsSubtypeReduction.js Records emit and declarations.

🧠 Review effort: Balanced

Comment thread tsc/internal/checker/checker.go Outdated
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The optimization changes core subtype-reduction semantics and warrants final human validation despite comprehensive regression coverage.

0 open findings

2 resolved since last review

🧠 Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Milestone Bug PRs that fix a bug with a specific milestone

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

IntelliSense slow down with large json file

3 participants