Skip to content
v0.4.1 · open source, MIT licensed

A TypeScript compiler, written in Rust.

Scanner, parser, binder, type checker, emitter and language server in one Cargo workspace. Every change is measured against the upstream TypeScript test suites, with the real tsc baselines as the oracle.

100% of JavaScript emit baselinesLSP server and VS Code extensionRuns in the browser as WebAssembly
$ tsc-rs --strict --target es2022 --module esnext queue.ts0 errors
queue.ts
export enum Priority {
  Low,
  High,
}

interface Job<T> {
  id: number;
  payload: T;
  priority: Priority;
}

export class Queue<T> {
  private jobs: Job<T>[] = [];

  push(payload: T, priority = Priority.Low): Job<T> {
    const job: Job<T> = { id: this.jobs.length + 1, payload, priority };
    this.jobs.push(job);
    return job;
  }

  next(): Job<T> | undefined {
    return this.jobs.shift();
  }
}
queue.js
export var Priority;
(function (Priority) {
    Priority[Priority["Low"] = 0] = "Low";
    Priority[Priority["High"] = 1] = "High";
})(Priority || (Priority = {}));
export class Queue {
    jobs = [];
    push(payload, priority = Priority.Low) {
        const job = { id: this.jobs.length + 1, payload, priority };
        this.jobs.push(job);
        return job;
    }
    next() {
        return this.jobs.shift();
    }
}
Status at a glance

Measured, not claimed.

tsc-rs runs the TypeScript project's own compiler, conformance and fourslash suites. A case passes only when the output matches what tsc produced. Skipped cases are never counted as passes.

100%
JavaScript emit
11,420 of 11,420 baselines match the tsc .js output byte for byte.
66.7%
Diagnostics
8,298 of 12,436 cases match every message, position and code.
71.3%
Language server
1,686 of 2,363 fourslash checks across five operations.
3,514
Rust tests passing
Zero failures and 37 ignored across the workspace, including documentation tests.

Emit and diagnostics as of the wave of 27 September 2026, measured with the cache disabled. Language server and test figures are the last recorded run. Read the full conformance report

One workspace

The whole toolchain, not just a transpiler.

Most Rust TypeScript tools stop at stripping types. tsc-rs implements the compiler end to end, then adds the modes that tooling needs.

Compiler and emitter

JavaScript, source map and declaration emit for ES3 through ESNext, with CommonJS, ESM, AMD, UMD and SystemJS module output.

$ tsc-rs -p tsconfig.json

Type checker

Inference, narrowing, relations and diagnostics that reproduce tsc's messages, positions and codes. Incomplete, and measured case by case.

$ tsc-rs --noEmit --strict

Language server

Diagnostics, hover, go-to-definition, references, completions, signature help, rename and formatting over stdio, plus a VS Code extension.

$ tsc-rs --lsp

Preserve modes

Keep type annotations, comments or the original layout in the emitted JavaScript for runtime type libraries and refactoring tools.

$ tsc-rs --preserveTypeAnnotations

Pipe and daemon modes

A persistent transpile pipe and a type-check daemon that speak newline-delimited JSON, built for bundlers, editors and agents.

$ tsc-rs --check-pipe -p tsconfig.json

Monorepo analysis

Parser-level import graph audits: find unreachable or type-only externals and the files with the widest dependency fan-out.

$ tsc-rs analyze dep-graph --entry src
Architecture

Five stages, one crate each.

The compiler is a plain pipeline. Each stage is its own crate with its own tests, and the tooling crates build on the same five.

01tsc_rs_scanner

Lexer

02tsc_rs_parser

Parser with tsc-compatible error recovery

03tsc_rs_symbols

Binder and symbol table

04tsc_rs_types

Type checker: inference, narrowing, relations

05tsc_rs_emitter

JavaScript, source map and declaration emit

.ts .tsx .js.js .d.ts .js.map
  • tsc_rs_astAST, spans, diagnostics, compiler options
  • tsc_rs_resolverModule resolution
  • tsc_rs_projecttsconfig, project graph, references, .tsbuildinfo
  • tsc_rs_incrementalIncremental build metadata and change detection
  • tsc_rs_queryQuery facade used by tooling
  • tsc_rs_serverLSP server
  • tsc_rs_cliThe tsc-rs binary
  • tsc_rs_harnessBaseline harness and reports
  • tsc_rs_benchScanner, parser and emitter benchmarks
  • tsc_rs_wasmWebAssembly build of the compiler
  • tsc_rs_analyzeStatic analysis for TypeScript monorepos

How the crates fit together

Performance

In the same league as the fastest native parsers.

One same-session comparison on typescript.js, a 7.8 MB fixture. Lower is better. The benchmarks live in crates/tsc_rs_bench so you can run them yourself.

Parse

Source text to AST.

tsc-rs
44.5 ms
oxc
35.2 ms

Parse and semantic analysis

AST plus binding and symbol resolution.

tsc-rs
96.0 ms
oxc
97.9 ms
2 to 4xTranspile-only emit with --fast-emit skips type checking and formatting normalization.
Every filetsc-rs parses faster than SWC on every file in the benchmark set.
48 MBPeak memory while checking 1,000 compiler diagnostic cases on one thread.

oxc parses faster; tsc-rs is ahead once semantic analysis is included. Method and raw timings are in the verified waves log.

Tooling first

Keep the types when you need them.

tsc throws all type information away. tsc-rs can carry some of it into the output, so downstream tools see what the author wrote.

  • Type annotations. Keep as, satisfies and angle-bracket assertions in the emitted JavaScript.
  • Comments. Keep comments even when removeComments is set.
  • Whitespace. Keep the original layout (partial).
tsc-rs --preserveTypeAnnotations cast.ts
const raw = JSON.parse("{}") as { port: number };
const config = { port: raw.port, host: "localhost" } satisfies Record<string, string | number>;
export const port = <number>config.port;
tsc-rs cast.ts
const raw = JSON.parse("{}");
const config = { port: raw.port, host: "localhost" };
export const port = config.port;
In production

The TypeScript front end of bext.

tsc-rs is not a lab project. It compiles every page and module served by the bext engine, including the one you are reading.

PRISM compiles with it

The bext PRISM renderer uses the tsc-rs parser, AST and emitter crates to turn TSX routes into the JavaScript it runs in V8.

One long-lived process

The persistent pipe transforms modules one JSON line at a time and reports imports, dynamic imports and exports with each result.

Errors fail the build

Parser diagnostics are reported even in transpile-only mode, so a broken source file stops the compile instead of shipping.

Limitations

What it is not, yet.

The tables on this site exist so you can judge the gaps for yourself. These are the ones that matter most today.

Not a drop-in tsc replacement

Diagnostics, declaration emit and expanded option variants are not at parity, and the CLI surface is a subset.

The type checker is incomplete

Hover types and some diagnostics differ from tsc. Expect missing errors and some false ones on advanced code.

Declarations and symbols are early

.d.ts output and the symbol baselines are the least mature lanes of the project.

Build it, point it at your project, read the numbers.

Install from source in one command, or compile a snippet in the playground without installing anything.