- JavaScript 49%
- WebAssembly 24%
- Shell 23%
- TypeScript 4%
typestrip #
A TypeScript type stripper in a small, dependency-free WebAssembly module.
typestrip erases types the way ts-blank-space and Node's type stripping do. Every JavaScript character stays where it was, so the output needs no source map. It streams, so memory stays flat at any input size. The engine is written in Zena and compiled to WasmGC with zero imports. It is 13.6 kB gzipped.
import { transform, transformSync } from "@nibling/typestrip";
await transform("let x: number = 1;"); // "let x = 1;"
transformSync("let x: number = 1;"); // the same, synchronously
// Stream chunks, a Node Readable, or a web ReadableStream.
for await (const piece of transform(fs.createReadStream("input.ts"))) out += piece;
Modes #
| Mode | Does | Preserves |
|---|---|---|
erase (default) |
Erases erasable syntax. Reports enum, instantiated namespace, parameter properties, import =, export =, and <T>x casts. |
Every offset |
downlevel |
Also down-levels that syntax, matching ts.transpileModule at runtime. |
Every line; columns outside converted constructs |
await transform(src, { mode: "downlevel" });
Pass jsx: true for .tsx input, in either mode. Erase mode keeps the JSX. Downlevel mode writes it for the classic runtime (React.createElement, or the pragma and pragmaFrag you pass, or a file's @jsx and @jsxFrag comments).
Unsupported syntax throws an UnsupportedSyntaxError with Node's ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX code. Pass onError to collect it instead. docs/modes.md has the full rules and examples of downlevel output.
Size #
Each mode loads its own engine, lazily, on its first call. Nothing loads at import.
| What you ship | Raw | gzip -9 | brotli -11 |
|---|---|---|---|
Erase mode: erase.wasm + wrapper |
32.8 + 6.4 kB | 13.6 + 2.9 kB | 12.4 + 2.6 kB |
Downlevel mode: downlevel.wasm + wrapper |
52.1 + 6.4 kB | 22.2 + 2.9 kB | 19.9 + 2.6 kB |
The wrapper is src/index.js bundled with esbuild --bundle --minify --format=esm. The browser entry is the same size. Both engines need WasmGC and wasm SIMD.
Speed #
On a 20MB sample of real-world TypeScript from 17 open-source projects (Apple M1, Node 24):
| Tool | MB/s | gzip |
|---|---|---|
| typestrip | 69.6 | 15.1kB |
| @swc/wasm-typescript (strip-only) | 27.3 | 1.39MB |
| amaro (strip-only) | 25.5 | 1.12MB |
| ts-blank-space | 16.9 | 1.03MB |
typestrip also beats oxc-transform, a native addon, in downlevel mode. It does less work per byte: one forward pass over the bytes, no syntax tree, and no code generation. docs/benchmarks.md has every tool, both modes, and the method.
Correctness #
Erase mode is judged against ts-blank-space, on positions, parsed JavaScript, error positions, and streamed output. It passes all 11,736 files of TypeScript 6's own sources and test suites. Downlevel mode is judged against ts.transpileModule by evaluating both outputs. docs/correctness.md lists every suite, its last result, and the open bugs.
Docs #
- API:
transform,transformSync, chunks, errors, loading in Node and browsers, concurrency - Modes: what each mode erases, reports, and down-levels
- Benchmarks
- Correctness
- Architecture: how the engine and wrapper work, the ABI, and the build
- Downlevel oracle: how
test/downlevel.mjsjudges downlevel mode - Glossary
Contributing #
CONTRIBUTING.md covers setup, building, testing, and the debug tools.