tsrs is a drop-in replacement for the TypeScript 7 compiler and language server, written in Rust.
Our goal is 100% conformance, with much lower memory use and faster type checking. Read the announcement.
pnpm add -D tsrs
pnpm exec tsrs --noEmitYou can try tsrs today and give us feedback on performance, memory usage, and conformance.
Try checking and emitting code in the browser playground.
We aim to release a stable version against TypeScript 7.1 with 100% conformance. See compatibility and evidence for supported features and known gaps.
Default mode preserves the pinned TypeScript compiler's checker behavior, including known diagnostic differences when checker count or file order changes. This sensitivity is inherited from TypeScript itself. See differences from pinned TypeScript for the remaining runtime differences and unsupported features.
The following defaults and opt-in preset are unreleased and available in source builds.
By default, tsrs follows the pinned TypeScript compiler's checker settings: four checkers (capped by file count),
Go's file assignment and checker history, and eager type members. Enable the fast preset with --fast or
TSRS_FAST=1:
pnpm exec tsrs --noEmit --fast
# Or enable the same preset through the environment:
TSRS_FAST=1 pnpm exec tsrs --noEmitWith no individual feature overrides, fast mode enables:
- Adaptive checker counts. One checker per core up to 16 cores; above that, the greater of 16 and half the
cores, rounded down. The count stays between 4 and 32 before file-count limits: small programs reduce it toward
4 to allow at least 32 checked files per checker, and it never exceeds the total file count.
--buildkeeps four checkers per project.--checkers Noverrides the count;--singleThreadeduses one. - Locality scheduling and work stealing. Groups nearby files on the same checker, starts heavy files first,
and lets idle checkers take unstarted work. Heavy declaration files can be checked in pieces across checkers.
Module affinity groups files that use the same modules, starting at 16 checkers, or 8 for programs with at
least 24,000 checked files. An explicit
--checkerAssignment/TSRS_CHECKER_ASSIGNMENTdisables stealing and file splitting. - Canonical checker history and additional caches. Changes selected history-dependent checks to reduce dependence on check order, and enables union-front, indexed-access and inference-walk caches.
- Lazy type members. Resolves and instantiates class/interface, mapped-type and tuple members as needed. Also defers conditional/inference mappers and property-cache allocation, and avoids unnecessary member instantiation during unmatched-property and empty-object checks.
- Lazy declaration parsing. Parses
.d.tsmember lists on first use whenskipLibCheckornoCheckis already enabled. Applies to batch and incremental compilation, and non-watch--buildwhen every built project skips declaration checking. Watch, language-server and API modes keep eager declaration parsing. - Freeing finished leaf files. Releases trees and binder data for selected unreferenced TypeScript modules during
non-incremental, non-watch
--noEmitcompilation, without declaration output or--explainFiles. Requires Unix with compressed pointers and a checker upper bound of at most 16, computed before files are loaded. It is disabled in--build.
The preset keeps strict, skipLibCheck, noCheck and other checking options as configured. Control-flow
memoization and parallel parsing are enabled in both modes. Memory targets and persistent checker-cost caches
still require an explicit size or path; experimental shared type graphs and TSRS_LAZY_HAS_PROP remain off.
Fast mode has these side effects:
- Check order can affect diagnostics. TypeScript itself has cases whose diagnostics depend on checker count or file order. Fast mode changes scheduling, checker history and lazy instantiation. In known check-order, recursive-type and instantiation-limit cases, errors can appear, disappear, move or have different message text, and the exit status can change. See the known cases.
- CPU and memory use change. Fast mode reduces memory use through lazy type members, lazy declaration parsing and freeing finished leaf files where eligible. Additional checkers and caches can offset those savings; the overall speed and peak-memory impact depends on the project.
- Compiler statistics change. Lazy member resolution and additional caches change the work performed, so type, symbol and instantiation counts can differ from TypeScript's. Work stealing can also make these counters vary between runs.
- Switching modes can require a fresh check. Incremental and build caches with incompatible checker-history or lazy-member settings are discarded, so the next build can take longer.
@tsrs/wasm provides WebAssembly support
targeting wasm32-wasip1 (WASI Preview 1).
- CLI usage and memory tuning
- Editor setup
- Node API
- WebAssembly for Node and browsers
- Benchmarks and methodology
- Release notes
- Engineering notes
The issue tracker is open for bug reports. Please include a minimal reproduction. Pull requests remain closed because we don't have the bandwidth to review them.
See the contributing guide for building from source and running the suites, the Code of Conduct, and security policy for reporting vulnerabilities.
We thank the following organizations and contributors:
- Depot CI for sponsoring our continuous integration.
- Owner.com for sponsoring the initial work.
- Max Schwenk for the port.
- @walkerdb for improvements to the project.
- @JiangWeixian for transferring the
tsrsnpm package name.
We extend special thanks to the TypeScript team for their support.
tsrs is a derivative of TypeScript (Copyright Microsoft Corporation), licensed under Apache-2.0.
The bundled lib.*.d.ts files are TypeScript's. See NOTICE for attribution.
Not affiliated with or endorsed by Microsoft.