tsrs, el port experimental de TypeScript a Rust, chequea tipos hasta 8 veces más rápido y con ~70% menos memoria, pero aún no es para producción. Sirve para medir y experimentar en un job paralelo, no para reemplazar a tsc en el pipeline que bloquea merges.
Qué es tsrs y qué no es
El 20 de octubre de 2026, Cloudflare y VoidZero presentaron tsrs, un port del compilador de TypeScript a Rust incubado en la cadena Oxc y desarrollado con el equipo de TypeScript (blog de Cloudflare). La palabra "port" importa: no es un fork. Un fork parte del código de Microsoft y se aleja con el tiempo; un port reescribe la lógica y se mide contra el original. Esa diferencia reduce el riesgo de terminar con un dialecto del lenguaje, aunque no lo elimina: la paridad entre dos implementaciones es trabajo de años.
Lo que tsrs no es:
- No es un bundler ni compite con Vite, esbuild o SWC.
- No es un transpilador. Su foco es el chequeo de tipos, no emitir JavaScript.
- No es estable. El propio repositorio lo presenta como experimental, sin versión estable (oxc-project/tsrs).
Si tu dolor es que el build tarda por el bundler, tsrs no lo resuelve. Si el dolor es el paso de tsc --noEmit en CI, ahí sí hay algo que mirar.
Qué mejora de verdad en el flujo de trabajo
El titular de 8× es un techo, no un promedio. Los benchmarks del anuncio comparan contra TypeScript 7.0 con el mismo número de workers, y ese detalle es lo primero que hay que verificar en cualquier medición propia: si tsc corre con un núcleo y tsrs con ocho, el resultado no dice nada útil.
El tiempo total de una corrida se reparte entre parseo, resolución de módulos, lectura de disco, chequeo y emisión. tsrs ataca el chequeo, que suele ser la porción dominante en repositorios grandes, pero no la única. En un proyecto con muchos node_modules, referencias de proyecto o un tsconfig con paths costosos, la resolución puede comerse una parte del pastel que ninguna reescritura en Rust acelera igual.
El dato que menos se repite y más importa es la memoria. Cerca de 70% menos consumo significa que el mismo runner puede sostener más jobs en paralelo, que los contenedores con límite bajo dejan de morir por OOM y que un monorepo que hoy necesita una máquina grande puede caber en una más pequeña. En CI, la memoria suele costar más que el tiempo: pagas por la instancia, no por el segundo.
Hay una tercera mejora que no aparece en el anuncio: si el chequeo es más rápido, el ciclo de edición se acorta cuando el checker alimenta al editor. Ojo: tsrs es un compilador, no el language server. Que su motor sea rápido no implica que tu extensión de VS Code ya lo esté usando.
Cómo medirlo en tu repositorio con --noEmit
Un protocolo de medición reproducible
La tentación es clonar el repo de moda, correr el benchmark y creerle. Mejor mide tu caso. Protocolo mínimo:
- Fija un commit y el lockfile. Nada de medir con
node_modulesa medio instalar. - Usa la misma versión de Node y el mismo sistema operativo en ambas corridas.
- Desactiva el cache incremental para comparar trabajo real, no aciertos de
.tsbuildinfo. - Corre cada comando varias veces y descarta la primera (arranque en frío).
- Registra tiempo de pared y memoria pico del proceso, no solo lo que reporta la herramienta.
Para la línea base:
# TypeScript 7.x
npx tsc --noEmit --incremental false --extendedDiagnostics
--extendedDiagnostics imprime Check time, Total time y Memory used, según la referencia oficial de tsconfig. Ese último número es la contabilidad interna del compilador; para comparar contra otro binario conviene mirar el RSS del sistema:
/usr/bin/time -v npx tsc --noEmit --incremental false
Y para repetir con estadística en vez de una sola corrida:
hyperfine --warmup 2 --runs 5 \
'npx tsc --noEmit --incremental false' \
'./ruta/al/binario/tsrs --noEmit'
Los flags exactos de tsrs pueden cambiar porque el proyecto no tiene versión estable; revisa el README antes de copiar el comando.
El paso que casi nadie hace y que decide si el experimento vale: comparar diagnósticos. Un chequeo más rápido que se salta errores es peor que uno lento. Guarda la salida de ambos con --pretty false, ordena y compara:
npx tsc --noEmit --pretty false > tsc.log 2>&1; echo "tsc: $?"
./ruta/al/binario/tsrs --noEmit --pretty false > tsrs.log 2>&1; echo "tsrs: $?"
diff <(sort tsc.log) <(sort tsrs.log)
Si los conteos de error y los códigos de salida coinciden en varias ramas, tienes algo. Si no, tienes una pista de qué falta.
Por qué el WASM cambia el cálculo
tsrs corre en WebAssembly, así que puede ejecutarse en el navegador y en Workers. Eso abre casos que un binario nativo no cubre: validar tipos en un playground, en un editor web o en un Worker que recibe código de terceros antes de ejecutarlo.
Pero hay una pregunta que los titulares no responden: ¿el 8× sale del binario nativo o del build WASM? No es un detalle menor. WASM paga costos de copia entre la memoria lineal y el host, y el soporte de hilos depende de que el entorno habilite memoria compartida. Antes de prometerle velocidad a tu equipo, confirma en qué build se midió y mide ese mismo.
Por qué no reemplaza a tsc en producción todavía
Tres razones concretas:
- Paridad incompleta. Un port joven no cubre todos los rincones de
tsconfig: referencias de proyecto,declaration, mapas de declaración, transformadores personalizados. Si tu build depende de eso, no está. - Costo asimétrico del error. Un falso positivo molesta; un falso negativo deja pasar un bug a producción. La velocidad no compensa eso.
- Ecosistema.
ts-loader,ts-jest, las reglas tipadas de ESLint y los plugins del language server hablan con la API de TypeScript, no con un binario alterno.
La forma sensata de adoptarlo es un job en sombra: tsc sigue siendo la puerta que bloquea el merge y tsrs corre en paralelo reportando diferencias. Dos semanas de ese experimento te dan más información que cualquier benchmark.
Qué hacer esta semana
Elige el job de CI que más te duela, corre el protocolo anterior y anota tres números: tiempo de pared, RSS pico y número de diagnósticos. Después abre un job informativo con tsrs, sin bloquear, y compara durante unos días. Si la paridad se sostiene y la memoria baja, tendrás argumentos para discutirlo con el equipo; si no, habrás evitado una migración a ciegas.
Preguntas frecuentes
¿tsrs ya se puede usar en producción?
No. El proyecto se presenta como experimental y sin versión estable, así que su comportamiento y sus flags pueden cambiar. Úsalo para medir y para un job en sombra, no como reemplazo de tsc en el pipeline que bloquea merges.
¿Reemplaza a esbuild, SWC o Vite?
No. Esas herramientas transpilan y empaquetan sin chequear tipos. tsrs apunta al chequeo, que es otro paso del flujo. Puedes tener ambos: uno rápido para transformar y otro para verificar.
¿Por qué importa que esté escrito en Rust?
Porque permite paralelismo real y un uso de memoria más predecible que el del runtime actual, y porque se puede compilar a WASM. El lenguaje no es la meta: es el medio para bajar tiempo y memoria en repositorios grandes.
¿Cómo sé si mi repositorio se beneficia?
Mide con --noEmit --extendedDiagnostics, compara el RSS pico y revisa cuánto del tiempo total es chequeo y cuánto es resolución de módulos o emisión. Si el chequeo domina y la paridad de diagnósticos se mantiene, hay margen.
¿Tengo que cambiar mi tsconfig?
Depende de las opciones que uses. Las más comunes suelen estar cubiertas; las referencias de proyecto, los transformadores personalizados y la emisión de declaraciones son las que hay que confirmar en el repositorio antes de asumir paridad. Revisa el README de tsrs y corre tu tsconfig en un job en sombra antes de cambiar el pipeline.