Status: Experimental. Published on npm as
typescript-native-bridge.
A faster typescript you can drop into any project (measure on your repo; no fixed speedup guarantee).
Swap the typescript package for this fork and keep using tsc, vue-tsc, ESLint, and your
editor as before. Type-checking runs on tsgo (Microsoft's Go TypeScript compiler) instead
of JavaScript. You do not need to learn tsgo, change imports, or add per-tool config.
TNB is a drop-in typescript replacement — not a separate tsgo CLI, not a new
LSP. One typescript override accelerates every tool that calls getTypeChecker() through
the standard Compiler API.
1. vue-tsc cannot use standalone tsgo
vue-tsc is built on the typescript programmatic API + Volar hooks (extraFileExtensions,
virtual getSourceFile for .vue, createProgram wrapping). Standalone tsgo / tsgo LSP does not speak that protocol — you cannot speed up vue-tsc by swapping the CLI to
tsgo. TNB keeps vue-tsc unchanged and routes createProgram → createTsgoProgram,
feeding Volar virtual content to Go via in-process overlays.
2. ESLint + typescript-eslint type-aware rules are checker-bound
@typescript-eslint/parser imports typescript and calls createProgram /
getTypeChecker() for type-aware rules. The bottleneck is the JS checker, not ESLint's
AST walk. TNB makes the parser pick up the fork automatically — no eslint config changes,
no separate tsgo lint pass.
3. Editors need tsserver + Language Service Plugins (not tsgo LSP)
Volar (@vue/typescript-plugin) runs as a tsserver LS Plugin. Microsoft's tsgo LSP
preview does not support that plugin model — migrating the editor means losing .vue
integration. TNB keeps stock tsserver + plugin host, swapping only the checker
backend to Go in-process.
| Tool | Still uses | Checker engine |
|---|---|---|
vue-tsc / tsc |
typescript API (_tsc.js) |
tsgo |
tsserver / VS Code |
typescript + LS Plugins |
tsgo |
@typescript-eslint/parser |
typescript API |
tsgo |
Compare with @typescript/native-preview: separate tsgo binary, change scripts, editor
uses experimental tsgo LSP — does not cover the three rows above with one override.
Use this if you just want to try TNB on an existing project:
- Add a
typescriptoverride (see below) - Run
pnpm install/npm install - Run your usual typecheck (
vue-tsc,tsc, ornuxi typecheck) - Confirm the TNB ACTIVE banner appears on stderr (first run per process)
- Editor: set
typescript.tsdkand switch to the workspace TypeScript version (see Editor / tsserver) - If no banner → see Troubleshooting
Put the override in pnpm-workspace.yaml at the repo root:
# 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 use catalog:typescript, update the catalog entry as well (see
Nuxt / Vue / monorepo notes).
// package.json
{
"resolutions": {
"typescript": "npm:typescript-native-bridge@<version>"
}
}# pnpm-workspace.yaml
overrides:
typescript: link:../typescript-native-bridgeBuild the fork first (npm run setup in the TNB repo). See Developing TNB.
After any override change: reinstall dependencies. The override applies repo-wide —
vue-tsc, @typescript-eslint/parser, and other transitive typescript users all pick
up the fork.
On the first type-check in a process, TNB prints this banner to stderr:
┌─────────────────────────────────────────────────────────┐
│ ✅ TNB ACTIVE — `typescript` is the tsgo-backed fork │
└─────────────────────────────────────────────────────────┘
No banner = stock typescript is still loaded. See Troubleshooting.
Quick sanity check:
node -e "console.log(require.resolve('typescript'))"
# should point at typescript-native-bridge, not node_modules/typescript@5.xStock typescript |
TNB | |
|---|---|---|
| Import | import * as ts from "typescript" |
Same |
| CLI | tsc, vue-tsc, nuxi typecheck |
Same commands |
| Per-tool config | — | None |
| Checker engine | JavaScript | Go (tsgo), in-process |
your tool → typescript (fork) → tsgo (Go)
same public API type-checking
└── in-process bridge (no child process, no IPC)
API compatibility: Existing tsc / vue-tsc / ESLint workflows work without code
changes. The checker is implemented by tsgo internally; tools that depend on deep
TypeScript internals or custom emit paths should be validated separately.
If your monorepo uses a catalog and any package depends on typescript via
catalog:, update the catalog entry as well as overrides: — otherwise those
packages may still resolve stock TypeScript even when root overrides is set:
# pnpm-workspace.yaml
catalog:
typescript: link:../typescript-native-bridge
overrides:
typescript: link:../typescript-native-bridgeMonorepo tip: Prefer workspace
overridesonly. A rootpnpm add -D typescript@link:...alone often does not replacevue-tsc's transitivetypescript.
Typical flow:
pnpm exec nuxi prepare # generate .nuxt types first
pnpm exec nuxi typecheck # or your package.json "typecheck" scriptSupported
import App from './App.vue'resolves to the.vuefile itself- Volar virtual TypeScript (content injected via
getSourceFilewhen the file isn't on disk) via overlay .vue,.svelte,.astro,.mdx, etc. through the standardextraFileExtensionscontract — no hard-coded.vuespecial caseallowArbitraryExtensionsinferredtruein tsgo when host extra extensions are present and tsconfig leaves the option unset (explicitfalseopts out)
Not supported
- Custom
resolveModuleNames/resolveModuleNameLiteralsthat remap an import to a different physical file (bridge is synchronous JS→Go; tsgo cannot call back into JS resolvers) - Explicit
allowArbitraryExtensions: falsein tsconfig → normalTS6263(opt-out)
CLI typecheck (vue-tsc, tsc) picks up TNB automatically after the override. The IDE
does not — VS Code / Cursor ship their own TypeScript and only use your fork when you
point typescript.tsdk at the workspace install and opt in to the workspace version.
After pnpm install, node_modules/typescript is TNB (same layout as stock
typescript: lib/tsserver.js, lib/typescript.js, …). The editor must load that
tsserver, not the built-in one.
1. Add workspace settings (commit .vscode/settings.json for the team):
// .vscode/settings.json — VS Code and Cursor
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}Use a path relative to the workspace folder that contains node_modules (monorepo:
usually the repo root). With pnpm overrides this resolves to TNB's lib/ even when the
physical path is a symlink.
2. Switch to the workspace version (required once per machine / workspace)
Command Palette → TypeScript: Select TypeScript Version → Use Workspace Version.
VS Code deliberately does not run workspace tsserver until you confirm (security). The
prompt appears on first open if typescript.enablePromptUseWorkspaceTsdk is set; otherwise
run the command manually.
3. Verify
- Status bar / TypeScript: Select TypeScript Version should show a path under
node_modules/typescript/lib, not "VS Code's Version". - Open a
.tsfile and trigger type-checking; View → Output → TypeScript may show TNB ACTIVE on first project load (same banner as CLI). - Vue/Nuxt: keep
@vue/typescript-pluginintsconfigcompilerOptions.pluginsas today — it runs as a tsserver LS Plugin on this fork; no separate tsgo LSP.
| Path | Bundle | Used by |
|---|---|---|
lib/_tsc.js |
CLI | tsc, vue-tsc -b |
lib/tsserver.js → lib/typescript.js |
Language service | IDE, tsserver, LS Plugins |
| CLI | IDE | |
|---|---|---|
| Needs override | Yes | Yes (same node_modules/typescript) |
| Extra config | No | typescript.tsdk + Use Workspace Version |
| Vue LS Plugin | via vue-tsc / program API |
via forked tsserver + @vue/typescript-plugin |
# 1. Confirm resolved package
node -e "console.log(require.resolve('typescript'))"
# 2. Typecheck + require banner (adjust command to your project)
pnpm exec vue-tsc -b --noEmit 2>&1 | tee /tmp/tsc.log
grep -F 'TNB ACTIVE' /tmp/tsc.log || { echo 'TNB not active'; exit 1; }Linux CI: The loader supports bridge.so / bridge.dll, but this repo may
only ship bridge.dylib until you build or publish per-platform binaries. Run
npm run build:bridge on the target OS, or ensure your package artifact includes
native/bridge.* for the runner (see Platform support).
Debug slow runs: TSGO_PROFILE=1 prints a [tsgo-profile] timing summary to stderr on process exit (not a .cpuprofile file).
| 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 (see above) |
| Stale install | pnpm install again; clear CI cache if needed |
| Wrong resolution | node -e "console.log(require.resolve('typescript'))" |
- CLI OK, IDE not: add Editor / tsserver (tsdk) settings and run TypeScript: Select TypeScript Version → Use Workspace Version. Override alone is not enough for the editor.
- IDE OK, CLI not: run
node -e "console.log(require.resolve('typescript'))"— should point at TNB. Reinstall after changing overrides. - CLI and IDE must both resolve the same
node_modules/typescript(same override at monorepo root).
TNB is experimental; tsgo parity with JS TypeScript is not 100%. Pin a version, diff results, and report gaps. This is expected during early adoption.
Error mentioning bridge.dylib / bridge.so / bridge.dll → run npm run setup in
this repo or ensure published artifacts include your platform.
| OS | Native library | Notes |
|---|---|---|
| macOS | native/bridge.dylib |
Primary dev target; may be the only prebuilt binary in a dev clone |
| Linux | native/bridge.so |
Build with npm run build:bridge on Linux for CI |
| Windows | native/bridge.dll |
Supported by loader; build on Windows |
End users of a published package need prebuilt binaries per platform. Contributors
build locally with Go + a C toolchain (npm run build:bridge).
Remove the typescript override from pnpm-workspace.yaml / package.json, reinstall,
and confirm:
pnpm install
node -e "console.log(require.resolve('typescript'))" # should be stock typescript@5.xNo source changes in your app are required to roll back.
Do I need to change my code?
No.
Do I configure vue-tsc or ESLint separately?
No. They import typescript; one override covers them.
Is this the same as @typescript/native-preview?
No. TNB replaces the full typescript package with an in-process Go bridge and Volar/SFC
integration. @typescript/native-preview ships the separate tsgo CLI (and preview JS
API) alongside stock typescript — you change scripts to call tsgo, not tsc.
How much faster is it?
Depends on project size and shape; large vue-tsc -b workloads are the main target.
Measure on your repo with and without the override.
End users can skip this section. Consuming a prebuilt clone (with
lib/+native/bridge.*already present) does not require Go. Building TNB from source in this repo requires Go, submodules, andnpm run setup.
git clone --recurse-submodules <repo>
cd typescript-native-bridge
npm run setup # submodules + vendor JS + native bridge + lib/| Script | Purpose |
|---|---|
setup |
Full first-time build (everything below) |
build:lib |
Daily: overlay → compile → LKG (~6s) |
build:ts |
Cold build (+ npm install in typescript submodule) |
build:js |
Compile typescript-go native-preview vendor (needed for bridge API types) |
build:bridge |
Rebuild Go native/bridge.{dylib,so,dll} |
patch:ts |
Apply patches/typescript/ to submodule |
patch:tsgo |
Apply patches/typescript-go/ to submodule |
refresh |
Re-apply both patch trees and run check:lib |
save-ts-patches |
Save typescript submodule changes → patches/typescript/ |
save-patches |
Save typescript-go submodule changes → patches/typescript-go/ |
check:lib-sync |
Verify overlay / submodule / lib/ are aligned |
check:enums |
Validate TS↔Go enum remapping tables |
patches/typescript/overlay/ ← TypeScript-side changes (edit here)
patches/typescript-go/overlay/ ← Go bridge changes (edit here)
↓ patch + build
lib/ JS bundles (typescript.js + _tsc.js)
native/ platform bridge binary
vendor/ native-preview JS (from build:js)
TypeScript overlay workflow
patches/typescript/overlay/
↓ npm run patch:ts (also run by build:lib)
typescript/ submodule ← do not edit by hand
↓ npm run build:lib
lib/typescript.js ← tsserver
lib/_tsc.js ← tsc, vue-tsc
Never hand-edit lib/*.js or typescript/src/. Always rebuild both bundles via
build:lib. Run npm run check:lib-sync before committing.
Go / bridge workflow
patches/typescript-go/overlay/
↓ npm run patch:tsgo
typescript-go/ submodule
↓ npm run build:bridge
native/bridge.*
After editing either submodule working tree: save-ts-patches or save-patches before commit.
git status will show typescript / typescript-go as modified after patch:ts /
patch:tsgo — that is expected (patches are applied to the submodule working tree, not
committed inside the submodule). Re-apply with npm run refresh after git submodule update.
Changing enums between TS and Go: run npm run check:enums.
Apache-2.0. See LICENSE and NOTICE.
This package is a derivative work of Microsoft TypeScript and microsoft/typescript-go.