¿Están equivocados los tipos de módulo?

This ad is not shown to multipass and full ticket holders
React Summit US
React Summit US 2025
November 18 - 21, 2025
New York, US & Online
The biggest React conference in the US
Learn More
In partnership with Focus Reactive
Upcoming event
React Summit US 2025
React Summit US 2025
November 18 - 21, 2025. New York, US & Online
Learn more
Bookmark
GithubProject website
Rate this content

¿Alguna vez has instalado una dependencia, la has importado tal como indica el README y te has encontrado inmediatamente con extraños errores de TypeScript sobre importaciones por defecto, el formato de módulo de salida o la interoperabilidad ESM/CommonJS? Cuando todo funciona en tiempo de ejecución pero TypeScript se queja, es posible que te preguntes, ¿es esto un error de TypeScript? O... ¿los tipos están equivocados?


El panorama de los módulos y la publicación de paquetes en JavaScript es complicado. Casi un tercio de los paquetes npm más populares que incluyen tipos tienen algún tipo de problema relacionado con los tipos de módulo que puede causar confusión a los usuarios. Pero las cosas están empezando a mejorar. En esta charla, vamos a:

- explorar cómo llegamos hasta aquí, ¿por qué las cosas son complicadas?
- desarrollar un modelo mental simple y preciso de cómo TypeScript ve los paquetes
- ver cómo la herramienta `arethetypeswrong` puede ayudar a detectar problemas antes de la publicación
- analizar las tendencias en los datos de `arethetypeswrong` para paquetes populares a lo largo del tiempo
- discutir los próximos pasos para mejorar el ecosistema de paquetes con tipos

This talk has been presented at TypeScript Congress 2023, check out the latest edition of this JavaScript Conference.

FAQ

ESM significa Módulo ECMAScript. Es el sistema de módulos que se incorporó a la especificación del lenguaje JavaScript en 2015, reconocible por las palabras clave 'import' y 'export'.

ESM (ECMAScript Module) y CommonJS son sistemas de módulos en JavaScript. ESM utiliza 'import' y 'export', mientras que CommonJS utiliza 'require' y 'module.exports'. CommonJS fue el estándar de la comunidad antes de la introducción de ESM y todavía es compatible con Node.js.

Node.js determina el formato de un archivo de módulo principalmente por la extensión del archivo: '.mjs' siempre es tratado como ESM, '.cjs' siempre como CommonJS, y '.js' depende del campo 'type' en el 'package.json' más cercano, siendo ESM si 'type' es 'module' y CommonJS de lo contrario.

Un archivo .d.ts en TypeScript es un archivo de declaración que contiene toda la información sobre los tipos y la estructura de un archivo JavaScript correspondiente, incluidos los tipos que han sido eliminados del archivo original de TypeScript.

Cuando se mezclan exportaciones predeterminadas en ESM y 'exports.default' en CommonJS, pueden surgir discrepancias, como que TypeScript espera una estructura de módulos mientras que Node.js ejecuta otra, llevando a errores o comportamientos inesperados en el tiempo de ejecución.

'rthetypeswrong' es una herramienta que analiza paquetes NPM para identificar discrepancias entre cómo TypeScript y Node.js resuelven los módulos, ayudando a detectar y resolver problemas de interoperabilidad entre ambos.

Para configurar un proyecto para usar módulos ES en Node.js, se debe agregar el campo 'type: module' en el archivo 'package.json'. Esto indica a Node.js que trate los archivos '.js' como módulos ECMAScript.

Andrew Branch
Andrew Branch
30 min
21 Sep, 2023

Comments

Sign in or register to post your comment.
Video Summary and Transcription
Esta charla analiza las complejidades y terminología del sistema de módulos, las discrepancias entre TypeScript y Node, y cómo solucionar los errores de TypeScript con el paquete Helmet. También explora la resolución de módulos y las discrepancias de tipos, los desafíos con el soporte de TypeScript y Node, y la necesidad de mejoras en paquetes populares.
Available in English: Are the (module) types wrong?

1. Introducción a los módulos y terminología

Short description:

Hola a todos. Mi nombre es Andrew y he estado en el equipo de TypeScript durante los últimos cuatro años. Hoy hablaremos sobre las complejidades del sistema de módulos y la terminología asociada, como ESM y CommonJS. Es importante estar familiarizado con las opciones de resolución de módulos y las diferencias entre Node.16 y Node.Next.

Muy bien. Hola a todos. Y gracias por unirse a mí para hablar sobre módulos. Mi nombre es Andrew. He estado en el equipo de TypeScript durante los últimos cuatro años, y tenemos mucho de qué hablar hoy en poco tiempo, así que eso es suficiente sobre mí. Y creo que todos sabemos que las complejidades del sistema de módulos son súper interesantes y divertidas, así que no hay tiempo para convencerte, pero si viste la charla de Mark Erickson y no tuviste suficiente, esta es definitivamente la charla para ti. Antes de comenzar, hay un poco de terminología que debemos cubrir. Voy a usar el término ESM o el acrónimo ESM alrededor de cien veces en esta charla. Eso significa Módulo ECMAScript. ESM es el sistema de módulos que se agregó a la especificación del lenguaje JavaScript en 2015. Y puedes reconocerlo por las palabras clave import y export. El otro sistema de módulos que discutiremos es CommonJS o CJS. Ese es el estándar de la comunidad que fue popularizado por Node antes de que existiera ESM. Si alguna vez has visto require y module.exports, eso es CommonJS y aún es compatible con Node. También tendré que mencionar algunas extensiones de archivo durante esta charla. Y como pueden superponerse con otros acrónimos, intentaré recordar pronunciarlos con un punto al principio. Será algo útil si estás al menos vagamente familiarizado con algunas opciones de resolución de módulos y TypeScript. Node.16 y Node.Next son actualmente idénticos, así que puedo llamarlos por cualquiera de los dos nombres. Son la única buena opción para Node moderno y no solo significa emitir módulos ES. Esa es una idea equivocada común. Históricamente, el que se llamaba Node era el que todos usaban para casi todo, pero realmente

2. Entendiendo el error de TypeScript con Helmet

Short description:

Vamos a analizar un confuso error de TypeScript con la dependencia de NPM Helmet. Cuando se compila a CommonJS, todo funciona bien. Sin embargo, al cambiar a módulos ES, se produce un error en el que helmet ya no se puede llamar. Vamos a investigar más a fondo ejecutando el código.

Helmet no se ha mantenido al día con las características modernas. Vamos a echar un vistazo a un error de TypeScript un tanto confuso aquí. Estoy mirando la dependencia de NPM llamada Helmet. Acabo de copiar y pegar el ejemplo del archivo README aquí. Esto se compila con TSC y se ejecuta en Node sin problemas. Puedes ver que actualmente estoy compilando a CommonJS. Si quiero cambiar a módulos ES aquí, puedo hacerlo agregando el campo type module a mi propio package JSON para el proyecto. Pero cuando hago eso y vuelvo aquí, ahora obtengo este confuso error de TypeScript que dice que helmet ya no se puede llamar. Si juego lo suficiente con esto, veré TypeScript

3. Entendiendo la Discrepancia entre TypeScript y Node

Short description:

Esta parte discute la discrepancia entre TypeScript y Node al importar el paquete Helmet. Explica cómo TypeScript y Node determinan el formato de archivo y las relaciones entre diferentes tipos de archivos en JavaScript. También explora qué sucede al exportar e importar código transpilado de ESM a CommonJS.

Estoy ejecutando esto. Esto no se ve bien para mí, pero vamos a ejecutarlo y ver qué sucede. Sí, esto se bloquea en Node. Por otro lado, si volvemos a la forma en que estaba donde typescript se queja, pero ejecutamos esto, funciona perfectamente. Parece haber una discrepancia aquí entre typescript y Node, y no podemos satisfacer a ambos al mismo tiempo. Al ver esto, es razonable preguntarse si esto es un error de typescript o si los tipos están mal. Para determinar eso por nosotros mismos, primero necesitamos aprender algunas cosas de antecedentes. La primera es cómo typescript y Node saben qué archivo estamos mencionando cuando decimos importar helmet o require helmet. Será más fácil de explicar esto con el campo de exportación y el archivo package JSON cuando volvamos al código, así que dejémoslo por un momento. La segunda es la detección del formato del módulo. Creo que mencioné que Node admite tanto ESM como CommonJS, por lo que necesita una forma de determinar qué archivo es de qué formato, y lo hace puramente por la extensión del archivo. Un archivo .mjs siempre será ESM, un archivo .cjs siempre será CommonJS, y un archivo .js, tenemos que consultar el package JSON más cercano y si tiene el campo especial type module, será ESM, de lo contrario, CommonJS. Muy bien. La tercera cosa son las relaciones entre los diferentes tipos de archivos con los que trata JavaScript. Cuando ejecutas TSC en un archivo input.ts, obtienes un archivo output.js y un archivo output.d.ts, que se llama archivo de declaración. Cuando publicas código para que otras personas lo consuman, generalmente quieres enviarles el código JavaScript compilado sin procesar. De esa manera, su tiempo de ejecución no necesita otro paso de compilación antes de ejecutarlo. Pero luego si ese usuario también está usando TypeScript ellos mismos, o simplemente un editor con funciones de lenguaje inteligente impulsadas por TypeScript, quieres darles este archivo de declaración, que contiene todo lo que necesita saber sobre el archivo JavaScript, incluyendo los tipos que se han eliminado del archivo original de TypeScript. Debido a que estos dos resultados se producen juntos al mismo tiempo, cuando el compilador o editor del usuario ve un archivo de declaración, um, en realidad ni siquiera necesita ir a buscar y asegurarse de que el archivo JS existe. Debido a esta relación, simplemente puede asumir que existe, saber todo lo que necesita saber sobre la estructura y los tipos, y también la extensión del archivo. Cuando ve .d.ts, sabe que debe haber un archivo .js allí. Y lo mismo ocurre con las extensiones de archivo específicas del formato que discutimos anteriormente. Un archivo .mts produce un archivo .mjs, y obtenemos un archivo .d.mts junto a eso. Y luego tenemos un análogo para las versiones de CommonJS aquí. Puede parecer que estoy enfatizando un punto relativamente simple aquí, pero te sorprendería la cantidad de problemas que tienen como causa raíz el romper esta relación de alguna manera.

Lo siguiente que necesitamos aprender es qué sucede si intentamos compilar esta exportación predeterminada a CommonJS. Las exportaciones predeterminadas en ESM son solo una forma especial de importación con nombre con una sintaxis especial adjunta. Entonces, lo único que haremos es adjuntar una asignación de propiedad con nombre aquí en module.exports con el valor que estamos exportando. Y luego también definiremos esta bandera aquí que simplemente dice, hey, he sido transpilado de ESM a CommonJS. Nuestro archivo de declaración, por otro lado, conserva esta sintaxis de ESM. Bien, casi terminado aquí. Lo último que necesitamos ver es qué sucede cuando intentamos importar esa misma exportación predeterminada transpilada que acabamos de ver. Entonces aquí tenemos nuestra exportación predeterminada transpilada a CommonJS nuevamente. Y si estamos importando esto en otro archivo que también se está compilando a CommonJS, entonces tiene sentido que lo que deberíamos obtener con una importación predeterminada allí sea el valor que exportamos por defecto.

4. Entendiendo las Importaciones y Exportaciones Predeterminadas en Node

Short description:

La importación predeterminada y la exportación predeterminada deben coincidir. Al importar un módulo CommonJS en Node, se devuelve todo el objeto module.exports. Para diagnosticar el error entre TypeScript y Node, debemos examinar los archivos que están buscando, comenzando con el archivo package.json de Helmet.

La importación predeterminada y la exportación predeterminada deben coincidir. Así que solo debería obtener hola mundo. Y las transformaciones que se aplican al compilar esto desde una importación predeterminada a una declaración require aseguran que eso se cumpla. Por otro lado, cuando hacemos esto en un módulo ES real en node, node no entiende que nuestro módulo de exportación aquí está fingiendo ser ESM. Y en node, cuando importas por defecto un módulo CommonJS, lo que obtendrás siempre es todo el objeto module.exports.

Entonces aquí, puedes ver que he registrado el module.exports y obtengo un objeto con una propiedad llamada default. Y eso es lo mismo que obtendría en node si hiciera una importación predeterminada real de esta falsa exportación predeterminada. Obtendría la propiedad module.exports con este default. Bien, ahora deberíamos saber lo suficiente como para poder diagnosticar este error por nosotros mismos. Si queremos entender la diferencia entre TypeScript y node, necesitamos saber qué archivos están buscando cada uno de ellos.

Entonces, primero, veamos el archivo package.json de Helmet. Bien, tenemos este campo de exportaciones nuevamente que mencionamos brevemente antes. Lo que vamos a hacer aquí es echar un vistazo a esta clave de punto. Y esto coincide con la ruta. Entonces, como estoy importando Helmet y no como Helmet slash utils, la ruta de punto coincide y entraremos aquí y veremos algunas condiciones. Así que vamos a fingir que estamos resolviendo como node primero. Estamos resolviendo una importación, no un require. Y lo que node va a hacer es mirar cada una de estas condiciones de arriba a abajo y seguir hasta que encuentre una que coincida. Entonces, la importación coincide porque estamos resolviendo una importación. Así que entraremos en este objeto y veremos algunas condiciones anidadas. Los tipos no coinciden. No es una de las condiciones que node establece aquí. Así que lo omitirá y comprobará el valor predeterminado. El valor predeterminado siempre coincide con todo. Entonces, node se resolverá a index dot MJS. Ahora, si estamos resolviendo como TypeScript, hacemos exactamente el mismo proceso con una excepción. TypeScript siempre coincide con la condición de tipos. Por lo general, no es necesario establecer la condición de tipos a menos que coloques todos tus archivos de declaración en un directorio completamente separado del JavaScript. Pero está aquí y coincide. Entonces, TypeScript se resolverá a index dot D dot TS.

5. Resolviendo la Discrepancia de Formato y Arreglando los Tipos

Short description:

Por cierto, hay una bandera de línea de comandos para TypeScript llamada trace resolution. Esto mostrará todo lo que está sucediendo. Ahora que sabemos qué archivos están en juego, hablemos del formato por un momento. Tenemos una discrepancia de formato. Si TypeScript supiera que este archivo está intentando tipar un módulo ES real, vería esta exportación como helmet por defecto y sabría que cuando lo importemos por defecto, funcionará como esperamos. Pero lo que TypeScript piensa es que este archivo representa un archivo Common JS que hace exports.default igual a helmet. Si soy el autor de la biblioteca, parece que todo está funcionando en tiempo de ejecución y solo necesito cambiar algo en la configuración de los tipos para solucionar este problema. El autor de la biblioteca Helmet ya ha solucionado este problema y lo ha resuelto mucho antes de que comenzara esta charla, por eso me siento cómodo analizándolo un poco en una conferencia. En lugar de repetir el trabajo que hizo y arreglar los tipos para que coincidan con el JavaScript existente, podría ser más divertido e instructivo para nuestros propósitos intentar romper el JavaScript existente para que coincida con los tipos existentes. La forma en que lo haré es comenzar haciendo que las extensiones coincidan. Sabemos que el archivo index.d.ts representa un archivo .js, así que eliminaré la M aquí. Y nuestra demostración no va a tocar el lado de require, pero haré que coincida también. Bien, el index.js que acabamos de poner aquí en realidad aún no existe. Así que lo crearé. Y como dijimos antes, sabemos que este archivo debe ser Common JS. Así que comenzaremos copiando el contenido de index.cjs aquí y asumiremos que está bastante cerca y luego lo comprobaremos. Vimos que teníamos esa exportación helmet por defecto, que vemos representada aquí como exports.default igual a helmet. Así que esto se ve bien. Creo que el único problema aquí es que esta línea está sobrescribiendo eso.

Por cierto, hay una bandera de línea de comandos para TypeScript llamada trace resolution. Esto mostrará todo lo que está sucediendo. Así que no tienes que recordar esto si solo quieres ver a qué está resolviendo TypeScript.

Ahora que sabemos qué archivos están en juego, hablemos del formato por un momento. Sabemos que node en este archivo .js lo interpretará como ESM debido a la extensión de archivo. El archivo .d.ts, por otro lado, sabemos que representa un archivo .js debido al triángulo que vimos antes en los tipos de archivo de TypeScript. Y el formato de ese archivo .js se determinaría por el campo module en el archivo package.json, pero no hay ninguno aquí en este package.json en ningún lugar. Así que sabemos que ese archivo JavaScript debe ser Common JS. Aquí tenemos una discrepancia de formato.

El archivo index.mjs de node sabemos que debe ser ESM y el archivo de declaración de tipos sabemos que representa un archivo Common JS. Y si echamos un vistazo a los propios tipos, nos preocupa esta parte de la exportación helmet por defecto. Y esto termina de explicar lo que estábamos viendo. Si TypeScript supiera que este archivo está intentando tipar un módulo ES real, vería esta exportación como helmet por defecto y sabría que cuando lo importemos por defecto, funcionará como esperamos. Sabes, tenemos una exportación por defecto. La importamos por defecto y la podemos usar sin problemas. Pero lo que TypeScript piensa es que este archivo representa un archivo Common JS que hace exports.default igual a helmet. Y si ese es el caso, cuando lo importemos por defecto en Node, todavía necesitaremos hacer ese .default adicional para acceder a la propiedad exports.default ya que solo estamos obteniendo la vista de module.exports en su totalidad.

Entonces, si soy el autor de la biblioteca, parece que todo está funcionando en tiempo de ejecución y solo necesito cambiar algo en la configuración de los tipos para solucionar este problema. Pero para revelar un pequeño spoiler, el autor de la biblioteca Helmet ya ha solucionado este problema y lo ha resuelto mucho antes de que comenzara esta charla, por eso me siento cómodo analizándolo un poco en una conferencia. Así que en lugar de repetir el trabajo que hizo y arreglar los tipos para que coincidan con el JavaScript existente, podría ser más divertido e instructivo para nuestros propósitos intentar romper el JavaScript existente para que coincida con los tipos existentes. La forma en que lo haré es comenzar haciendo que las extensiones coincidan. Sabemos que el archivo index.d.ts representa un archivo .js, así que eliminaré la M aquí. Y nuestra demostración no va a tocar el lado de require, pero haré que coincida también. Bien, el index.js que acabamos de poner aquí en realidad aún no existe. Así que lo crearé. Y como dijimos antes, sabemos que este archivo debe ser Common JS. Así que comenzaremos copiando el contenido de index.cjs aquí y asumiremos que está bastante cerca y luego lo comprobaremos. Vimos que teníamos esa exportación helmet por defecto, que vemos representada aquí como exports.default igual a helmet. Así que esto se ve bien. Creo que el único problema aquí es que esta línea está sobrescribiendo eso.

6. Solucionando el Error de TypeScript con Helmet

Short description:

Nos encontramos con un error de TypeScript al usar el paquete Helmet. Al realizar cambios en el código JavaScript, pudimos hacer coincidir los tipos y resolver el error. Este patrón de una biblioteca CommonJS asignando a exports.default es común, y los tipos advierten correctamente a los usuarios que están importando en Node.esm. Para simplificar el proceso de análisis, creé una herramienta llamada rthetypeswrong que verifica la resolución de módulos e identifica las discrepancias entre TypeScript y el tiempo de ejecución. Helmet 7.0 ha resuelto los problemas al tipar correctamente los archivos index.cjs e index.mjs.

Entonces, simplemente vamos a eliminarlo. Y creo que ahora deberíamos tener acuerdo. Volviendo a nuestro archivo de entrada, recordemos que no tocamos los tipos en absoluto. Aún esperamos ver este error de TypeScript, pero lo que deberíamos ver es que si TypeScript nos está dando un error, Node también se va a bloquear. Así que vamos a construir y ejecutar eso. Y sí, esta vez, helmet no es una función. Y si en cambio hacemos lo que TypeScript nos está diciendo que deberíamos hacer, helmet.default, y luego construimos y ejecutamos esto, esto ahora funciona.

Ok, ¿por qué pasamos por este tipo de ejercicio tonto de hacer un cambio probablemente indeseable en el JavaScript para que coincida con los tipos? Bueno, a veces cuando las personas me presentan un problema como este y les explico lo que está sucediendo en los tipos, dirán algo así como, sabes, parece que TypeScript está siendo demasiado pedante aquí. Claramente podía encontrar los tipos antes, y mi JavaScript de CommonJS y ESM son casi idénticos. Así que si TypeScript puede encontrar el archivo, simplemente, ya sabes, entiende lo que quiero decir y no me hagas pasar por tantos obstáculos. Pero lo que hemos demostrado aquí es que los tipos no están incorrectos per se. No son inválidos. Simplemente describen una biblioteca diferente a la que teníamos aquí. Describen la que acabamos de hacer a través de nuestros cambios. Y este patrón de, esencialmente, una biblioteca CommonJS que asigna a exports.default es bastante común. Es posible que el autor de la biblioteca no haya tenido la intención de hacer esto, pero lo he visto varias veces en la práctica. Y cuando los tipos para eso son correctos, advierte correctamente a los usuarios que están importando en Node.esm que necesitarán de manera no intuitiva, pero legítimamente, este extra.default para acceder a lo que creen que necesitan acceder. Entonces, aunque todos ustedes ahora son expertos en resolución de módulos e interoperabilidad, puede ser demasiado pedir que todos los usuarios o incluso todos los autores de bibliotecas sean expertos en este tema.

Así que hice una herramienta que puede hacer parte de este análisis por ti. rthetypeswrong es una herramienta que descarga un paquete NPM y luego, para cada modo de resolución de módulos admitido por TypeScript, realiza esencialmente el análisis que acabamos de hacer manualmente. Verifica a qué está resolviendo el compilador de TypeScript y a qué está resolviendo el tiempo de ejecución, analiza cada uno de esos archivos y verifica las discrepancias. Aquí estábamos viendo Helmet 6.1.2 y vemos que cuando estamos importando desde ESM en el modo Node 16, resolvemos a tipos de CommonJS pero JavaScript de ESM. Y eso es exactamente lo que vimos. Y mencioné que Helmet ya ha solucionado esto. Así que echemos un vistazo a eso. En Helmet 7.0, no vemos problemas y CommonJS se resuelve a CommonJS y ESM a ESM. Esto se ve genial. Y como no nos molestamos en arreglar los tipos nosotros mismos, podemos ver cómo el autor de la biblioteca solucionó esto. Aquí vemos que tanto los archivos index.cjs como index.mjs ahora están tipados con su propio archivo de declaración con la extensión correcta. Así que TypeScript puede ser consciente de todos los archivos que están allí y conocer los formatos de todo.

7. Analizando la Resolución de Módulos y las Discrepancias de Tipos

Short description:

Ahora hay una versión de línea de comandos de la herramienta, lo que facilita su integración en los procesos de publicación o la verificación de paquetes locales. Probamos los cambios realizados en Helmet utilizando la herramienta y solucionamos las discrepancias entre los tipos y JavaScript. Sin embargo, la versión ESM se resuelve a la versión Common JS, lo cual no es el resultado deseado. Al analizar los paquetes de npm a lo largo del tiempo, se observan mejoras para los usuarios en todos los grupos, excepto para los usuarios de node ESM, que enfrentan errores en más de una cuarta parte de las dependencias de tipos. Los problemas en la lista ESM incluyen declaraciones de CommonJS que intentan representar JavaScript de ES y resoluciones sin tipos. Este último es un problema más grave, ya que TypeScript no puede encontrar las declaraciones de tipos que se envían con el paquete. Estos problemas pueden ser relativamente fáciles de solucionar, a diferencia de otros que requieren ajustes en los sistemas de compilación. Los problemas surgen de la adopción rápida de la sintaxis ESM antes de que los implementadores y TypeScript se pusieran al día, lo que llevó a suposiciones incorrectas sobre la interoperabilidad de los dos formatos. Las soluciones alternativas para la falta de soporte de TypeScript también se convirtieron en problemas cuando TypeScript introdujo los modos Node-16 y Node-next. Es importante tener en cuenta que cuando se consideran incorrectos los tipos de un paquete, no se trata de un juicio sobre las publicaciones anteriores.

También hay una versión de línea de comandos de esta herramienta ahora. Por lo tanto, es fácil integrarla en su proceso de publicación o verificar un paquete local. Por diversión, probemos eso en los cambios que hicimos en Helmet. Ejecutaré attw y luego pack, y lo ejecutaremos en node-module-slash-helmet. Puedes ver aquí que hemos solucionado las discrepancias, no se encontraron problemas entre los tipos y JavaScript, pero a diferencia de la versión anterior, a diferencia de en Helmet 7, podemos ver que la versión ESM de las cosas se resuelve a la versión Common JS de la biblioteca. Eso no es un problema, pero no es la solución que probablemente Helmet quería hacer, que era, ya sabes, hacer que ESM se resuelva al ESM que ya está allí.

Lo bueno de hacer todo este análisis en los paquetes npm es que nos brinda una forma natural de ver muchos datos a lo largo del tiempo. Ejecuté rthetypeswrong en los 6,000 principales paquetes npm tal como existían el primero de cada mes desde enero del año pasado, desglosados por algoritmo de resolución de módulos. Podemos ver que las cosas están mejorando para los usuarios en todos los grupos aquí, con la ligera excepción del aumento reciente en node 10, que proviene de paquetes que dejan de admitir esto. Por otro lado, las cosas no se ven bien para los usuarios de node ESM, con más de una cuarta parte de las dependencias de tipos mostrando algún tipo de error. Esto nos pone en una situación difícil, porque si la comunidad va a migrar a ESM, y creo que debería hacerlo, pero de todos modos, ya está sucediendo. Sería muy bueno si pudiéramos animar a los usuarios a hacer esa transición primero antes que las bibliotecas, pero eso es difícil de vender como usuario de TypeScript si hacer el cambio va a romper una cuarta parte de tus dependencias.

Si desglosamos los problemas que estamos viendo en esa lista ESM de problemas aquí, podemos ver un poco más de matices. Esta línea verde es el tipo de problema que acabamos de ver, donde las declaraciones de CommonJS intentan representar JavaScript de ES. Parece que esto está aumentando a largo plazo, pero por otro lado, está intercambiando uno por uno con esta línea naranja, que son resoluciones sin tipos. Esto significa que el paquete estaba enviando declaraciones de tipos, pero TypeScript no pudo encontrarlas en absoluto. Y ese es un problema peor, aunque los números agregados no lo demuestren realmente. No tenemos tiempo para entrar en qué son cada uno de estos problemas que el tipo fuerte puede detectar, pero señalaré que el segundo problema más frecuente aquí, a diferencia de algunos de los otros, creo que son relativamente fáciles de solucionar la mayor parte del tiempo. Algunos de los otros requieren ajustes en los sistemas de compilación, y estos a menudo son solo una corrección de una línea. Tienen que ver con mezclar export equals y export default en archivos de declaración. Entonces, ¿de dónde vienen todos estos problemas en primer lugar? Las lagunas en esta línea de tiempo son la mejor explicación que se me ocurre. Escribir sintaxis ESM se volvió increíblemente popular muy temprano en 2014, antes de que se publicara la especificación final de ESM en 2015. Y esto es normal, probar características del lenguaje temprano es parte del proceso de TC39. Pero lo que vimos fue una adopción muy rápida de escribir código ESM en la comunidad con un largo retraso antes de que los implementadores pudieran ponerse al día. Y luego otro largo retraso después de eso antes de que TypeScript pudiera ponerse al día con Node. En todo este tiempo, ya sea que lo supieran o no, las herramientas que te permiten escribir sintaxis ESM y generar common.js estaban codificando estas suposiciones implícitas sobre cómo iban a interoperar esos dos formatos en tiempo de ejecución real. Y no todas esas suposiciones resultaron ser correctas. Al mismo tiempo, entre 2019 y 2022, cuando los paquetes querían enviar ESM y declaraciones de tipos, tuvieron que idear soluciones alternativas para la falta de soporte de TypeScript aquí. Pero una vez que TypeScript se puso al día y lanzó los modos Node-16 y Node-next, esas soluciones alternativas se convirtieron en problemas en sí mismas. Es importante entender que cuando digo que los tipos son incorrectos para un paquete, no es un juicio sobre lo que se publicó en el pasado.

8. Desafíos con el Soporte de TypeScript y Node

Short description:

Muchos de los problemas que vemos se pueden atribuir al soporte rezagado de TypeScript para Node. Me he estado enfocando en este espacio de problemas durante aproximadamente un año, trabajando en difundir información y mejorando la herramienta ¿Los Tipos están Equivocados?. Ahora, estoy buscando tener un impacto más directo en los problemas existentes en los paquetes populares.

Es solo una observación sobre lo que funciona o no funciona ahora. De hecho, muchos de los problemas que vemos tienen sus raíces en el soporte rezagado de TypeScript para Node. Por lo tanto, este espacio de problemas ha sido mi principal enfoque durante la mayor parte de un año. Hasta ahora, la mayor parte de lo que he estado haciendo ha sido para difundir información desde ¿Los Tipos están Equivocados? hasta la documentación oficial de TypeScript. Creo que esa fase de mi trabajo está llegando a su fin y tengo algunas mejoras en el plan de ¿Los Tipos están Equivocados? de las que estoy emocionado. Pero anticipando un cambio hacia la búsqueda de formas de tener un impacto más directo en algunos de los problemas existentes que vemos en los paquetes populares. Entonces, si ya estás familiarizado con este espacio o simplemente quieres aprender y participar en eso, por favor contáctame y podemos intentar solucionar algunos de estos problemas juntos. Si eres un autor de bibliotecas, te recomiendo encarecidamente que ejecutes ¿Los Tipos están Equivocados?, la CLI, como parte de tu proceso de publicación para que puedas detectar algunos de estos problemas antes que tus usuarios, y si eres un usuario y notas uno de estos errores extraños en una de tus dependencias y ¿Los Tipos están Equivocados? puede detectar que algo está sucediendo aquí, considera abrir un problema contra la biblioteca. Solo recuerda buscar duplicados y proporcionar una reproducción clara y, lo más importante, sé amable con los mantenedores. Te advertí al principio que esta charla iba a ser bastante abstracta y ligera en consejos prácticos. Así que intentaré terminar con algunas recomendaciones concretas. En primer lugar, en mi opinión, es hora de adoptar ESM solo para nuevos proyectos. Al menos, no asumas automáticamente que necesitas enviar CommonJS. Cuando solo produces un formato de módulo y especialmente cuando es ESM y especialmente cuando lo produces con TSC, prácticamente estás garantizado de estar inmune a todos los diferentes tipos de problemas que ¿Los Tipos están Equivocados? puede detectar en las bibliotecas populares. En segundo lugar, si estás interesado en más validación como parte de tu proceso de publicación, recomiendo publint.dev como contraparte de ¿Los Tipos están Equivocados?. Cubre un montón de reglas no relacionadas con TypeScript que puedes verificar para asegurarte de que estás configurando correctamente tu package JSON. Y luego no tuvimos tiempo para entrar en esto, pero creo que hay muchas razones por las que deberías pensarlo dos veces antes de publicar un paquete dual ESM CommonJS. Pero si es necesario, te recomiendo investigar DNT, que es el publicador de paquetes de Deno para Node. Tiene algunas características únicas, como ejecutar tu conjunto de pruebas de Deno tanto en los paquetes de salida CommonJS como ESM. Eso puede darte una mayor confianza, especialmente cuando lo combinas con algo como ¿Los Tipos están Equivocados?, para que si te encuentras con un problema que se está introduciendo en tus paquetes, lo detectarás antes de publicarlo. Por último, este es un tema en el que veo mucha negatividad y sentimientos de impotencia. No puedo negar que estas cosas pueden ser complicadas, pero definitivamente no son más difíciles que aprender un nuevo framework de front-end cada semana o hacer aritmética en el espacio de tipos o centrar verticalmente un div. Veo a todos ustedes haciendo cosas impresionantes y complicadas todos los días, y sugiero que veas este tipo de espacio desordenado como una oportunidad para aprender cosas nuevas o incluso convertirte en un experto en un área que realmente necesita más expertos. Así que, gracias por escuchar y nos vemos en la sesión de preguntas y respuestas y en las salas de discusión.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Vite: Repensando las Herramientas de Frontend
JSNation Live 2021JSNation Live 2021
31 min
Vite: Repensando las Herramientas de Frontend
Top Content
Vite is a next-generation build tool that leverages native ES modules for improved performance. It eliminates the need for bundling and improves hot module replacement. Vite provides an opinionated default configuration while still allowing advanced customization through plugins. It is framework agnostic and can be used for React and other applications. Vite is being adopted by Next.js and Create React App, and integration with Nuxt 3 offers significant speed improvements.
Escalando con Remix y Micro Frontends
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Escalando con Remix y Micro Frontends
Top Content
This talk discusses the usage of Microfrontends in Remix and introduces the Tiny Frontend library. Kazoo, a used car buying platform, follows a domain-driven design approach and encountered issues with granular slicing. Tiny Frontend aims to solve the slicing problem and promotes type safety and compatibility of shared dependencies. The speaker demonstrates how Tiny Frontend works with server-side rendering and how Remix can consume and update components without redeploying the app. The talk also explores the usage of micro frontends and the future support for Webpack Module Federation in Remix.
Compilador React Forget - Entendiendo React Idiomático
React Advanced 2023React Advanced 2023
33 min
Compilador React Forget - Entendiendo React Idiomático
Top Content
Joe Savona
Mofei Zhang
2 authors
The Talk discusses React Forget, a compiler built at Meta that aims to optimize client-side React development. It explores the use of memoization to improve performance and the vision of Forget to automatically determine dependencies at build time. Forget is named with an F-word pun and has the potential to optimize server builds and enable dead code elimination. The team plans to make Forget open-source and is focused on ensuring its quality before release.
Los tipos más útiles de React
React Day Berlin 2023React Day Berlin 2023
21 min
Los tipos más útiles de React
Top Content
Today's Talk focuses on React's best types and JSX. It covers the types of JSX and React components, including React.fc and React.reactnode. The discussion also explores JSX intrinsic elements and react.component props, highlighting their differences and use cases. The Talk concludes with insights on using React.componentType and passing components, as well as utilizing the react.element ref type for external libraries like React-Select.
Componentes de Full Stack
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Componentes de Full Stack
Top Content
RemixConf EU discussed full stack components and their benefits, such as marrying the backend and UI in the same file. The talk demonstrated the implementation of a combo box with search functionality using Remix and the Downshift library. It also highlighted the ease of creating resource routes in Remix and the importance of code organization and maintainability in full stack components. The speaker expressed gratitude towards the audience and discussed the future of Remix, including its acquisition by Shopify and the potential for collaboration with Hydrogen.
TypeScript y React: Secretos de un matrimonio feliz
React Advanced 2022React Advanced 2022
21 min
TypeScript y React: Secretos de un matrimonio feliz
Top Content
React and TypeScript have a strong relationship, with TypeScript offering benefits like better type checking and contract enforcement. Failing early and failing hard is important in software development to catch errors and debug effectively. TypeScript provides early detection of errors and ensures data accuracy in components and hooks. It offers superior type safety but can become complex as the codebase grows. Using union types in props can resolve errors and address dependencies. Dynamic communication and type contracts can be achieved through generics. Understanding React's built-in types and hooks like useState and useRef is crucial for leveraging their functionality.

Workshops on related topic

React, TypeScript y TDD
React Advanced 2021React Advanced 2021
174 min
React, TypeScript y TDD
Top Content
Featured Workshop
Paul Everitt
Paul Everitt
ReactJS es extremadamente popular y, por lo tanto, ampliamente soportado. TypeScript está ganando popularidad y, por lo tanto, cada vez más soportado.

¿Los dos juntos? No tanto. Dado que ambos cambian rápidamente, es difícil encontrar materiales de aprendizaje precisos.

¿React+TypeScript, con los IDEs de JetBrains? Esa combinación de tres partes es el tema de esta serie. Mostraremos un poco sobre mucho. Es decir, los pasos clave para ser productivo, en el IDE, para proyectos de React utilizando TypeScript. En el camino, mostraremos el desarrollo guiado por pruebas y enfatizaremos consejos y trucos en el IDE.
Dominando conceptos avanzados en TypeScript
React Summit US 2023React Summit US 2023
132 min
Dominando conceptos avanzados en TypeScript
Top Content
Featured WorkshopFree
Jiri Lojda
Jiri Lojda
TypeScript no es solo tipos e interfaces. Únete a esta masterclass para dominar características más avanzadas de TypeScript que harán tu código a prueba de balas. Cubriremos tipos condicionales y notación de inferencia, cadenas de plantillas y cómo mapear sobre tipos de unión y propiedades de objetos/arrays. Cada tema se demostrará en una aplicación de muestra que se escribió con tipos básicos o sin tipos en absoluto y juntos mejoraremos el código para que te familiarices más con cada característica y puedas llevar este nuevo conocimiento directamente a tus proyectos.
Aprenderás:- - ¿Qué son los tipos condicionales y la notación de inferencia?- ¿Qué son las cadenas de plantillas?- Cómo mapear sobre tipos de unión y propiedades de objetos/arrays.
Domina los Patrones de JavaScript
JSNation 2024JSNation 2024
145 min
Domina los Patrones de JavaScript
Top Content
Featured Workshop
Adrian Hajdin
Adrian Hajdin
Durante esta masterclass, los participantes revisarán los patrones esenciales de JavaScript que todo desarrollador debería conocer. A través de ejercicios prácticos, ejemplos del mundo real y discusiones interactivas, los asistentes profundizarán su comprensión de las mejores prácticas para organizar el código, resolver desafíos comunes y diseñar arquitecturas escalables. Al final de la masterclass, los participantes ganarán una nueva confianza en su capacidad para escribir código JavaScript de alta calidad que resista el paso del tiempo.
Puntos Cubiertos:
1. Introducción a los Patrones de JavaScript2. Patrones Fundamentales3. Patrones de Creación de Objetos4. Patrones de Comportamiento5. Patrones Arquitectónicos6. Ejercicios Prácticos y Estudios de Caso
Cómo Ayudará a los Desarrolladores:
- Obtener una comprensión profunda de los patrones de JavaScript y sus aplicaciones en escenarios del mundo real- Aprender las mejores prácticas para organizar el código, resolver desafíos comunes y diseñar arquitecturas escalables- Mejorar las habilidades de resolución de problemas y la legibilidad del código- Mejorar la colaboración y la comunicación dentro de los equipos de desarrollo- Acelerar el crecimiento de la carrera y las oportunidades de avance en la industria del software
Consejos y Trucos Profundos de TypeScript
Node Congress 2024Node Congress 2024
83 min
Consejos y Trucos Profundos de TypeScript
Top Content
Featured Workshop
Josh Goldberg
Josh Goldberg
TypeScript tiene un sistema de tipos poderoso con todo tipo de características sofisticadas para representar estados de JavaScript salvajes y extravagantes. Pero la sintaxis para hacerlo no siempre es sencilla, y los mensajes de error no siempre son precisos al decirte qué está mal. Vamos a profundizar en cómo funcionan muchas de las características más poderosas de TypeScript, qué tipos de problemas del mundo real resuelven, y cómo dominar el sistema de tipos para que puedas escribir código TypeScript verdaderamente excelente.
Mejores Prácticas y Consejos Avanzados de TypeScript para Desarrolladores de React
React Advanced 2022React Advanced 2022
148 min
Mejores Prácticas y Consejos Avanzados de TypeScript para Desarrolladores de React
Top Content
Featured Workshop
Maurice de Beijer
Maurice de Beijer
¿Eres un desarrollador de React tratando de obtener los máximos beneficios de TypeScript? Entonces esta es la masterclass para ti.En esta masterclass interactiva, comenzaremos desde lo básico y examinaremos los pros y contras de las diferentes formas en que puedes declarar componentes de React usando TypeScript. Después de eso, pasaremos a conceptos más avanzados donde iremos más allá de la configuración estricta de TypeScript. Aprenderás cuándo usar tipos como any, unknown y never. Exploraremos el uso de predicados de tipo, guardias y comprobación exhaustiva. Aprenderás sobre los tipos mapeados incorporados, así como cómo crear tus propias utilidades de mapa de tipo nuevo. Y comenzaremos a programar en el sistema de tipos de TypeScript usando tipos condicionales e inferencia de tipos.
Uso de CodeMirror para construir un editor de JavaScript con Linting y AutoCompletado
React Day Berlin 2022React Day Berlin 2022
86 min
Uso de CodeMirror para construir un editor de JavaScript con Linting y AutoCompletado
Top Content
Workshop
Hussien Khayoon
Kahvi Patel
2 authors
Usar una biblioteca puede parecer fácil a primera vista, pero ¿cómo eliges la biblioteca correcta? ¿Cómo actualizas una existente? ¿Y cómo te abres camino a través de la documentación para encontrar lo que quieres?
En esta masterclass, discutiremos todos estos puntos finos mientras pasamos por un ejemplo general de construcción de un editor de código usando CodeMirror en React. Todo mientras compartimos algunas de las sutilezas que nuestro equipo aprendió sobre el uso de esta biblioteca y algunos problemas que encontramos.