Published on npm as
typescript-native-bridge.
A drop-in typescript replacement that type-checks on Go. Swap the typescript
package for this fork and keep using tsc, vue-tsc, svelte-check, astro-check,
glint, ESLint, and your editor exactly as before — the checker runs on tsgo
(Microsoft's Go TypeScript compiler) in-process instead of JavaScript. No new CLI, no
new LSP, no per-tool config, no code changes.
typescript@7 is Microsoft's Go-native rewrite — but it doesn't drop into the tools you
actually use:
vue-tsc/astro-check/svelte-check/glintare built on the classictypescriptprogrammatic API (createProgram, Volar hooks, custom hosts). v7's programmatic surface is the new tsgo API — not a drop-in replacement for the classic one, so those tools can't just move to it.- ESLint (typescript-eslint) imports the classic
typescriptAPI and callsgetTypeChecker()— same API mismatch. - Editors run
tsserver+ Language Service Plugins (@vue/typescript-pluginfor.vue) — tsgo's LSP doesn't support that plugin model.
TNB keeps the classic package surface and puts the v7 engine (tsgo 7.x) behind it
in-process — so one typescript override accelerates all of them at once.
# pnpm-workspace.yaml
overrides:
typescript: npm:typescript-native-bridge@<version>pnpm install
pnpm exec vue-tsc -b --noEmit # or your project's typecheck scriptIf packages depend on typescript via catalog:, update the catalog entry too,
or those packages still resolve stock TypeScript:
catalog:
typescript: npm:typescript-native-bridge@<version>
overrides:
typescript: npm:typescript-native-bridge@<version>Use the alias and the $typescript override reference as shown — putting
npm:typescript-native-bridge@… directly inside overrides is rejected or mis-resolved
by some npm versions (issue #8). <version> is an exact version
(e.g. ^6.0.3-bridge.0.tsgo.7.0.2) or the latest dist-tag.
// package.json
{
"resolutions": {
"typescript": "npm:typescript-native-bridge@<version>"
}
}# pnpm-workspace.yaml
overrides:
typescript: link:../typescript-native-bridgeThe checkout must be built first (requires Go — npm run setup in the TNB repo).
After any override change: reinstall. The override applies repo-wide — vue-tsc,
@typescript-eslint/parser, and every other transitive typescript consumer picks up
the fork.
On the first type-check in a process, TNB prints to stderr:
┌─────────────────────────────────────────────────────────┐
│ ✅ TNB ACTIVE — `typescript` is the tsgo-backed fork │
└─────────────────────────────────────────────────────────┘
No banner = stock typescript is still loaded. See Troubleshooting.
node -e "console.log(require.resolve('typescript'))"
# should point at typescript-native-bridge, not node_modules/typescript@6.xVerified means: the tool runs on the fork and its output matches stock typescript@6.0.3
on the stated workload (no crash, no silent under-reporting, no false positives beyond
the known differences).
| Tool | Status | Verified on |
|---|---|---|
tsc |
✅ | compiler test corpus |
vue-tsc |
✅ | elk.zone monorepo (~2,000 files): emitted-error parity with stock, ~3.1× faster |
astro-check |
✅ | fixture project: output identical to stock |
svelte-check |
✅ | fixture project: output identical to stock (incl. svelteHTML ambient shims) |
glint |
✅ | fixture project: same error set as stock (transformed .gts virtual files) |
| ESLint + typescript-eslint (type-aware rules) | ✅ | 1,000-file type-aware corpus: lint output byte-identical to stock |
tsserver + @vue/typescript-plugin |
✅ | volar language-tools test suite: 205/205 pass |
tsslint |
✅ | runs as the volar repo's own linter |
Continuous verification: a nightly CI gate replays 19,028 language-service probe
units (quickinfo / definition / references / diagnostics) against the same stock
build — no new divergences allowed. If your tool isn't listed, try it and file an issue;
the fork covers any tool that drives the standard typescript Compiler API.
.vue,.svelte,.astro,.mdx,.gtsetc. via the standardextraFileExtensionscontract — no hard-coded per-framework special case.- Host-injected virtual content (Volar virtual TS, glint's transformed modules, svelte's ambient shims) reaches the Go checker.
allowArbitraryExtensionsis inferredtruewhen host extra extensions are present and tsconfig leaves it unset; explicitfalseopts out.- Not supported: custom
resolveModuleNames/resolveModuleNameLiteralsthat remap an import to a different physical file (the bridge is synchronous JS→Go; tsgo cannot call back into JS resolvers).
Measured on this repo's benchmarks (Apple Silicon; your repo will differ — measure):
| Workload | Stock typescript |
TNB | |
|---|---|---|---|
vue-tsc -b full check (elk.zone, ~2000 files) |
9.7s | 3.1s | ~3.1× |
| type-aware ESLint, single-run (plain TS, one program) | 7.6s | 7.7s | parity |
| JS heap peak (1000-file type-aware ESLint run) | 1.57GB | 0.90GB | −43% |
The rule is simple: wherever the time is in the checker, TNB is faster. The Go engine does the whole-program semantic pass ~10× faster than the JS checker — the question for any workload is how much of its time that phase is.
vue-tsc -b (checker-dominated — the big win):
| Stock | TNB | |
|---|---|---|
| Type-checking | ~5.6s (JS checker) | ~0.6s (Go checker) |
| Tool overhead (Volar codegen, JS, transport) | ~4.1s | ~2.5s |
| Total | 9.7s | 3.1s |
The single-run ESLint row is the control case: its type-checking share is small (the tool spends its time on parsing, AST conversion and rule execution — work both sides pay), so the total lands at parity. Workloads dominated by transport volume rather than checker work (e.g. watch-mode ESLint issuing ~469K tiny queries — one program rebuild per linted file) measure the JS↔Go boundary, not the engine; the V8-arena transport (fixed-layout records written straight into V8 memory, DataView reads, interned strings) keeps that boundary near its floor, and memory stays well below stock either way.
CLI typecheck picks up TNB automatically. The editor does not — VS Code ships its own TypeScript and only uses yours when you opt in.
1. Workspace settings (commit .vscode/settings.json for the team):
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}Use a path relative to the workspace folder that contains node_modules.
2. Switch to the workspace version (once per machine):
Command Palette → TypeScript: Select TypeScript Version → Use Workspace Version.
3. Verify: the version picker shows a path under node_modules/typescript/lib; the
Output → TypeScript channel may show TNB ACTIVE on first project load. Vue/Nuxt users:
keep @vue/typescript-plugin in tsconfig compilerOptions.plugins as today — it runs
as a tsserver LS Plugin on this fork.
| CLI | Editor | |
|---|---|---|
| Override needed | Yes | Yes (same node_modules/typescript) |
| Extra config | No | typescript.tsdk + Use Workspace Version |
The checker is tsgo, so behavior is not yet bit-for-bit identical to the JS checker. Across 19,028 replayed language-service probe units (quickinfo / go-to-definition / find-all-references / diagnostics on a real-world Vue fixture corpus), 1,097 (5.8%) currently differ from the pinned stock build — all triaged and attributed (display formatting, result ordering, cross-file reference residuals, intentional deviations). The breakdown is tracked in #2 — known differences. Emitted-error parity on a large real-world Vue monorepo is exact. If you hit a difference not listed in the tracker, please file an issue with a minimal repro.
The bridge binary ships as per-platform optional dependencies; npm install pulls only
the one matching your machine (the main package is pure JS):
| Platform | Sub-package |
|---|---|
| macOS Apple Silicon | @typescript-native-bridge/darwin-arm64 |
| macOS Intel | @typescript-native-bridge/darwin-x64 |
| Linux x64 | @typescript-native-bridge/linux-x64 |
| Linux arm64 | @typescript-native-bridge/linux-arm64 |
| Linux arm (32-bit) | @typescript-native-bridge/linux-arm |
| Windows x64 | @typescript-native-bridge/win32-x64 |
| Windows arm64 | @typescript-native-bridge/win32-arm64 |
On an unsupported platform the loader fails with a clear "unsupported platform or
missing optional dependency" error — build from source there (clone with submodules,
then npm run setup; requires Go + a C toolchain).
| Check | Action |
|---|---|
| Override at workspace root | Monorepo: pnpm-workspace.yaml, not a leaf package |
| pnpm 11 | Move package.json → pnpm.overrides to pnpm-workspace.yaml → overrides: (pnpm 11 no longer reads the pnpm field — silently ignored) |
catalog: pin |
Update catalog and overrides |
| Stale install | pnpm install again; clear CI cache if needed |
| Wrong resolution | node -e "console.log(require.resolve('typescript'))" |
- CLI OK, editor not: add the tsdk settings and run TypeScript: Select TypeScript Version → Use Workspace Version. The override alone is not enough for the editor.
- Editor OK, CLI not: check
require.resolve('typescript')— should point at TNB. Reinstall after changing overrides.
Check Known differences first — if yours isn't listed, pin a version, diff results, and file an issue.
Error mentioning bridge.dylib / bridge.so / bridge.dll / "unsupported platform" →
see Platform support (build from source, or use a link: install
built with npm run setup).
TSGO_PROFILE=1 prints a [tsgo-profile] RPC/timing summary to stderr on process exit.
Remove the typescript override, reinstall, confirm:
pnpm install
node -e "console.log(require.resolve('typescript'))" # stock typescript@6.x againNo source changes required.
Do I need to change my code? No.
Do I configure vue-tsc / ESLint / my editor plugin separately? No. They import
typescript; one override covers them.
Is this the same as TypeScript 7 / tsgo? Same engine, different package. TNB pins
tsgo 7.x as its checker (the version string ends in tsgo.7.0.2), but keeps the classic
typescript API and tsserver in front of it. typescript@7 gives you the new tsgo
API and its own LSP instead — see Why not just use TypeScript 7?
How much faster is it? See Performance — biggest on vue-tsc-style
full-program workloads. Measure on your own repo.
Apache-2.0. See LICENSE and NOTICE.
This package is a derivative work of Microsoft TypeScript and microsoft/typescript-go.