perf(typecheck): run the native TypeScript 7 compiler (#6356)

A bare `tsc` was silently resolving to the JavaScript TypeScript 6 compiler.
`apps/sim` depends on `@typescript/typescript6` for its runtime TypeScript AST
API, which pulls in `@typescript/old` (an alias of `typescript@6`) declaring its
own `tsc` bin. Package managers pick bin winners by lexical sort rather than
dependency depth, so `@typescript/old` beat `typescript` and won
`node_modules/.bin/tsc`.

Identical diagnostics, ~10x slower, and it fails silently: the check still
passes, it just burns minutes. Both compilers check an identical 11,066-source-
file program with byte-identical diagnostics; the only `--listFiles` delta is
lib relocation plus TS7 deduping nested .d.ts copies.

The `@typescript/native` alias sorts ahead of `@typescript/old` and reclaims the
bin. This is the TypeScript team's own recommendation on typescript-go#4567 --
the original blog example was wrong. Every `type-check` script is unchanged;
`bunx tsc` and ad-hoc invocations are fixed too.

apps/sim cold 83s -> 8.5s; all 23 workspaces 96s -> 9.4s.

The alias is invisible-load-bearing: nothing imports it, so removing it looks
like dead-dependency cleanup and costs 10x with no visible failure.
check:native-typecheck asserts a bare `tsc` reports 7.x and fails CI otherwise.

Also drops NODE_OPTIONS=--max-old-space-size=8192 from apps/sim's type-check --
it only ever mattered for the JS compiler's V8 heap.
This commit is contained in:
Waleed
2026-08-06 17:33:03 -07:00
committed by GitHub
parent f340ad965d
commit a512a263c8
14 changed files with 71 additions and 13 deletions
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bun
/**
* Asserts that a bare `tsc` runs the native (Go) TypeScript 7 compiler.
*
* `apps/sim` needs `@typescript/typescript6` for its runtime TypeScript API, and that
* package depends on `@typescript/old` — an alias of `typescript@6` — which declares its
* own `tsc` bin. Package managers pick bin winners by lexical sort rather than dependency
* depth, so `@typescript/old` beats `typescript` and `node_modules/.bin/tsc` silently
* becomes the JavaScript TypeScript 6 compiler: identical diagnostics, ~10x slower.
*
* The root `@typescript/native` alias exists purely to win that sort. Nothing imports it —
* deleting it costs every `tsc` invocation in the repo an order of magnitude, with no
* visible failure. This audit is what makes that regression loud.
*
* @see https://github.com/microsoft/typescript-go/issues/4567
*/
import { spawnSync } from 'node:child_process'
import path from 'node:path'
const ROOT = path.resolve(import.meta.dir, '..')
const BIN_TSC = path.join(ROOT, 'node_modules', '.bin', 'tsc')
const result = spawnSync(BIN_TSC, ['--version'], { encoding: 'utf8' })
const reported = result.stdout?.trim() ?? ''
if (!/^Version 7\./.test(reported)) {
const detail = reported || result.stderr?.trim() || `exit ${result.status}`
console.error('Native type-check audit failed:\n')
console.error(` node_modules/.bin/tsc reports "${detail}", expected TypeScript 7.x (native).`)
console.error(
'\n A bare `tsc` has fallen back to the JavaScript TypeScript 6 compiler that\n' +
' `@typescript/typescript6` pulls in transitively — same diagnostics, ~10x slower.\n' +
' Check that the `@typescript/native` alias is still in the root devDependencies,\n' +
' and that no newly added package sorts ahead of it while declaring a `tsc` bin.'
)
process.exit(1)
}
console.log(`Native type-check audit passed (bare \`tsc\` is ${reported}).`)