An experimental TypeScript port of the TypeScript 7.0.2 compiler (TypeScript-Go, or tsgo), compiled to native code with scriptc.
Install the compiler from npm:
npm install -D tsc-ts
npx tsc-ts -p tsconfig.jsonThe tsc-ts package runs a native executable from a per-platform optional dependency (@tsc-ts/darwin-arm64, @tsc-ts/linux-x64-gnu, …). See packages/tsc-ts.
See CHANGELOG.md for release notes and GitHub Releases for package archives.
To build the packages for the current platform:
npm run pack:npm -w tsc-ts # packages/tsc-ts/dist/npm/*.tgz
npm run pack:npm -w tsc-ts -- --check # also install the tarballs and compile a project-- --binary dist/tsc packs an existing native build, relative to packages/tsc-ts, instead of building one.
| Package | Description |
|---|---|
packages/tsc-ts |
The compiler, written in TypeScript, with the tsc-ts command line and --api server. |
packages/tsgo |
Reference builds of tsgo (its command line and per-stage drivers) that the tests compare against. |
Tasks run with Turborepo.
apps/web contains the tsc-ts compiler guides.
npm run dev:web
npm run build:web- Node.js 24+ and npm
- Go 1.26
- A scriptc host: macOS, Linux, or Windows, with
clangavailable for linking (on Windows, zig, which scriptc links with there and which compiles the--api --pipeserver,packages/tsc-ts/native/pipe-win32.c; on macOS and Linux,clangalso compiles the--api --listenserver,packages/tsc-ts/native/listen-posix.c)
npm ci
npm run fetch:upstream # clone tsgo at the pinned commit
npm run build # the Node build of tsc-ts (packages/tsc-ts/dist) and the documentation site
npm run build:oracle # tsgo reference builds in packages/tsgo/distpackage.json pins scriptc 0.4.8, with its @scriptc/threads package. The build fails with any other version.
packages/tsc-ts/src/compiler is the compiler, ported from tsgo 7.0.2 as idiomatic TypeScript. Each part is compared with tsgo on TypeScript's test corpus (about 12,500 files, 17,000 units after splitting multi-file cases):
| Part | Compared with tsgo | Status |
|---|---|---|
| Scanner | tokens, values, errors, rescans, JSDoc | all files match |
| Parser and AST | tree, diagnostics, API source file encoding | all units match |
| Binder | symbols, tables, flow graph, name resolution | all units match |
| Module resolution | results, package IDs, --traceResolution |
all requests match |
tsconfig.json and programs |
--showConfig, --listFilesOnly, --explainFiles |
all cases match |
| Command line and options | output, errors, exit codes, --locale |
all cases match |
| Diagnostics catalog | messages, 13 translations, output formats | all match |
| JavaScript emit | emitted files, 39 option sets | all compared units match |
| Declaration emit | .d.ts and .d.ts.map output, declaration errors |
all units match |
--build, --incremental |
output, .tsbuildinfo, emitted files, --watch |
all scenarios match |
| Type checker | diagnostics per file | all files match |
The corpus scripts are in packages/tsc-ts/scripts (*-corpus.mjs).
tsc-ts --api serves the same API as TypeScript 7.0.2's tsc --api, over stdin and stdout, so tools that drive tsc --api (such as scriptc) can run tsc-ts instead. On Windows the native executable also serves it over a named pipe it creates (--pipe \\.\pipe\<name>), as tsc --api --pipe does. On macOS and Linux it serves one client at a time on a Unix socket it creates (--listen <path>), keeping parsed files between clients.
npm run build -w tsc-ts
node packages/tsc-ts/dist/tsc-ts/src/main.js --api --cwd path/to/projectNative builds read lib files from the executable's directory, or from TSC_TS_LIB_DIR:
npm run build:native -w tsc-ts # packages/tsc-ts/dist/tsc
npm run build:native:dev -w tsc-ts # unoptimized, faster to build
TSC_TS_LIB_DIR=upstream/TypeScript/tsc/internal/bundled/libs packages/tsc-ts/dist/tsc -p path/to/projectbuild:native optimizes with a committed profile. npm run refresh-profile -w tsc-ts collects it again on Linux: it builds an instrumented tsc-ts, checks the tsc-ts sources and the eight projects in packages/tsc-ts/profiles/projects.json with it at --checkers 1 (tRPC, Playwright, TypeORM, Excalidraw, Sentry, VS Code, T3 Code server and T3 Code web, at pinned commits), and merges the results. The first run clones and installs the projects into ~/.cache/tsc-ts/profile-projects (--projects-dir chooses another directory); later runs reuse them. --project <dir>[:<tsconfig>] adds a project, and --jobs <n> sets how many checks run at once.
On Linux, the optimized build passes --exceptions=rare to scriptc: the check's recursive functions propagate an exception by native unwinding instead of testing a status after each of their calls. The committed profile is collected from builds with the same option (refresh-profile passes it to every build), since a profile describes the code of a build with a given setting. Other platforms keep scriptc's status checks.
The pinned scriptc has a second profile phase, so build:native builds with the two-phase profile packages/tsc-ts/profiles/tsc-ts.cs.profdata, and refresh-profile collects only that one. A scriptc without a second phase builds with the one-phase profile packages/tsc-ts/profiles/tsc-ts.profdata, which only such a scriptc collects: a scriptc with a second phase instruments different code, though it can report the same version.
packages/tsc-ts/profiles/tsc-ts.cs.json and tsc-ts.json record the scriptc that collected each profile, whether it has a second profile phase, and the number of functions the profile describes. tests/profile.test.mjs fails when neither profile was collected with the pinned scriptc, since the code scriptc generates changes between versions, or when the one-phase profile was collected with a scriptc that has a second profile phase. A profile from older tsc-ts sources still applies to the functions that did not change. build:native reports how many of the described functions the build annotates; below 95% it prints a warning, and below 90% it fails when the CI environment variable is set. Both messages name npm run refresh-profile -w tsc-ts, which takes about 4 minutes on 16 cores once the projects are installed. A scriptc that prints no profile report, or a tsc-ts.json without a function count, skips the check with a note. Windows builds print the match as a note without checking it: scriptc inlines its allocator's fast paths on Linux and macOS but not on Windows, so most functions there have different control flow from the profile collected on Linux.
TSC_TS_BIN=packages/tsc-ts/dist/tsc runs the tsc-ts tests that take a native build against it.
The server is checked against tsc --api 7.0.2 response by response, and scriptc builds the same programs with either. It runs on the tsc-ts compiler, natively or under Node.
Language service methods are supported: getCompletionsAtPosition, getImportAdderEdits, getJsDocTags, getDocumentationComment, getReferencesToSymbolInFile, getReferencedSymbolsForNode and getSignatureUsages. Completions include auto imports from the project and its dependencies, and getImportAdderEdits returns the edits that import symbols into a file, as in tsc --api. The profiling methods (startCPUProfile, stopCPUProfile, saveHeapProfile) are not supported.
npm test # compare tsc-ts with tsgo
npm run bench -w tsc-ts # time tsc-ts against tsgo and TypeScript's JavaScript compiler
npm run lint # oxlint
npm run format # oxfmtApache-2.0. See THIRD_PARTY_NOTICES.md for TypeScript-Go and other third-party notices.