Inicio / Artículos / TypeScript 7.0 pasa al compilador de Go para lograr una velocidad nativa

TypeScript 7.0 pasa al compilador de Go para lograr una velocidad nativa

TypeScript 7.0 adapta tsc a Go con verificadores en paralelo, nuevos valores predeterminados para tsconfig, literales de plantilla Unicode, un análisis de JS más estricto, y una brecha temporal en la API programática.

1086 palabras

Durante aproximadamente catorce años, el compilador de TypeScript pudo compilarse a sí mismo. tsc era TypeScript que se compilaba a JavaScript y funcionaba en Node. A medida que los repositorios crecieron hasta alcanzar millones de líneas, ese diseño autohospedado se convirtió en un cuello de botella.

TypeScript 7.0 cambia el lenguaje anfitrión. El compilador y el servicio de lenguaje pasaron de TypeScript a Go. Microsoft describe este trabajo como una adaptación y no como una reescritura: la estructura de verificación de tipos es similar a la de 6.0, pero la ejecución se realiza mediante código nativo con paralelismo de memoria compartida. Las comparaciones publicadas suelen indicar una aceleración de aproximadamente 10× en comparación con TypeScript 6.0.

Un caso de uso frecuentemente citado ilustra concretamente este cambio. La verificación del árbol de VS Code, que consta de alrededor de 1.5 millones de líneas en TypeScript, pasó de unos 77.8 segundos a aproximadamente 7.5 segundos.

Si las versiones anteriores utilizaban el nombre en código Project Corsa (con el árbol de JavaScript heredado apodado Strada), esta versión representa la materialización de ese esfuerzo.

¿Por qué Go, y por qué una adaptación?

La especulación pública solía mencionar a Rust. Se eligió Go porque se ajustaba a la estructura del compilador existente: gráficos complejos, recolección de basura y estructuras cíclicas que resultan difíciles de recrear desde cero. Ese ajuste hizo posible una adaptación línea por línea.

El marco de la adaptación es más importante que el nombre del lenguaje. Al mantener la arquitectura, se conservaron las reglas. Los proyectos que ya realizan comprobaciones de tipos bajo 6.0 con stableTypeOrdering activado y sin ignoreDeprecations deberían obtener los mismos resultados bajo 7.0: un motor más rápido, no un sistema de tipos diferente.

Primero se realizó la prueba de carga en producción. Durante más de un año, el puerto funcionó con estructuras complejas en plataformas como Bloomberg, Figma, Google, Slack, Notion y Vercel antes de alcanzar este hito.

Paralelismo real

Antes, un único hilo de Node limitaba el rendimiento. Los trabajadores nativos eliminan esa restricción. La versión 7 distribuye las tareas de análisis, verificación y emisión y añade flags:

  • --checkers establece la cantidad de trabajadores de verificación de tipos en paralelo
  • --builders paraleliza la compilación de referencias de proyectos y pilas con --checkers en monorepos
  • --singleThreaded concentra todo en un único núcleo para fines de depuración y medición de tiempos básicos

La cantidad de tareas de análisis/emisión por archivo aumenta según el tamaño y la modularidad del repositorio; las aplicaciones pequeñas de un solo archivo obtienen beneficios menores.

También se reconstruyó el modo de observación. La consulta constante agotaba la CPU en árboles enormes de node_modules; al utilizar el sistema de observación de Parcel en Go se reduce ese consumo y la aplicación reacciona más rápidamente a los cambios.

Cambios en la configuración que causarán problemas a los equipos

TypeScript 6.0 sirvió como puente: las nuevas configuraciones por defecto y las funciones obsoletas aparecían como advertencias. 7.0 las convierte en errores graves. Los equipos que ya pasaron por 6.0 han realizado la mayor parte del trabajo. Pasar directamente de 5.x a 7.0 requiere tiempo para limpiar tsconfig.json.

Cambios notables en las configuraciones por defecto:

  • strict está activado a menos que se modifique
  • module utiliza esnext, mientras que target elige la última versión estable de ECMAScript anterior a esnext
  • noUncheckedSideEffectImports está activo por defecto
  • libReplacement está desactivado por defecto
  • stableTypeOrdering permanece activado forzadamente
  • rootDir comienza en ./
  • types inicia como una lista vacía
  • La documentación señala que rootDir y types son los primeros problemas con los que se encuentran los equipos, y también aquellos para los cuales existen soluciones más sencillas.

    Si tsconfig.json se encuentra por encima de una carpeta src, establezca rootDir de forma explícita para que la estructura generada siga siendo familiar:

    {
      "compilerOptions": {
        "rootDir": "./src"
      },
      "include": ["./src"]
    }
    

    Dado que types ya no importa automáticamente todo lo que está bajo node_modules/@types, enumere solo lo que necesite:

    {
      "compilerOptions": {
        "types": ["node", "jest"]
      }
    }
    

    Las opciones que anteriormente emitían advertencias ahora causan errores graves (dejan de realizar cualquier función útil):

    • Elimine target: es5 y downlevelIteration
    • Sustituya los valores antiguos de moduleResolution (node, node10, classic) por nodenext o bundler
    • Elimine los modos module como amd, umd, systemjs y none en favor de esnext o preserve
    • Quite baseUrl y exprese las paths de forma relativa a la raíz del proyecto
    • No establezca esModuleInterop / allowSyntheticDefaultImports en false
    • Considere que alwaysStrict está activado de forma permanente

    Si después de años sin revisión moduleResolution sigue establecido en el valor antiguo node, ese archivo constituye la lista de verificación para la migración.

    Unicode en tipos de literales de plantilla

    Los tipos de plantillas literales ahora siguen los puntos de código Unicode en lugar de las unidades de código UTF-16:

    type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
    
    type Result = HeadTail<"😀abc">;
    // In 7.0:      ["😀", "abc"]
    // Previously:  ["\ud83d", "\ude00abc"]
    

    Los compiladores antiguos podían dividir una pareja sustituta de un emoji. Eso reflejaba el indexado de JavaScript y rara vez coincidía con la intención del autor. Ahora la iteración sigue los puntos de código, al igual que for...of y [...str]. Las herramientas que contaban intencionalmente las unidades UTF-16 dejarán de funcionar; todos los demás obtendrán el comportamiento que esperaban.

    Análisis más estricto de JavaScript

    La verificación de archivos .js solía tolerar más expresiones propias de JSDoc y de la época de Closure. La versión 7 refuerza ese enfoque hacia las reglas de .ts:

    • Los lugares que requieren tipos rechazan valores sin especificar tipo; se prefiere typeof someValue
    • @enum / @class pierden el tratamiento especial; se debe declarar una clase real o usar @typedef
    • Un simple ? no se acepta como tipo; se prefiere any
  • Las afirmaciones con ! al final no están soportadas; escriba T de forma explícita
  • Las formas antiguas de function(string): void han sido reemplazadas por (s: string) => void
  • La brecha en la API programática

    Todavía falta una API programática estable en la versión 7.0. Las bibliotecas que integran el compilador —la integración de TypeScript en ESLint, ts-morph, transformadores desarrollados manualmente, además de herramientas de editor para plantillas de Vue, Svelte, Astro, MDX o Angular— por lo tanto aún no pueden cambiar completamente. Microsoft considera este problema temporal y espera completar la API en las versiones 7.1 y posteriores.

    Mientras tanto, utilice la versión 7.0 cuando no se requieran los complementos de language-server. Los equipos de Angular, por ejemplo, pueden ejecutar tsc desde la versión 7.0 para realizar rápidas verificaciones en toda la aplicación mediante la CLI, manteniendo al mismo tiempo la versión 6.0 en el editor. Un paquete de compatibilidad, @typescript/typescript6, proporciona un binario tsc6 y reexporta la API de 6.0 para que ambas versiones puedan coexistir:

    {
      "devDependencies": {
        "typescript": "npm:@typescript/typescript6@^6.0.0"
      }
    }
    

    ¿Debería actualizar?

    Si ya está en TypeScript 6.0, la migración es sencilla y los beneficios son significativos: basta ajustar algunos parámetros de tsconfig para obtener pruebas continuas más rápidas y un inicio del editor más ágil. En versiones anteriores, los problemas de compatibilidad son reales, pero casi todos ya fueron señalados.

    Instale la versión candidata a lanzamiento hoy mismo:

    npm install -D typescript@rc
    

    En cuanto a los editores, hoy en día existe un complemento para VS Code que soporta LSP, y la integración nativa con VS Code sigue expandiéndose. Visual Studio detecta la versión 7.0 en el espacio de trabajo abierto sin necesidad de realizar un paso adicional de instalación.

    Los mantenedores afirman que las versiones con nuevas funcionalidades volverán a seguir el familiar ritmo de varios meses, y se espera que la versión 7.1 resuelva las deficiencias de la API de incrustación.

    Resultado final: reglas habituales de TypeScript, ejecutándose como código nativo.