Me di cuenta de que React
se puede importar así:
import * as React from 'react';
...o así:
import React from 'react';
El primero importa todo en el módulo de react
(ver: Importar el contenido de un módulo completo )
El segundo importa solo la exportación del módulo default
(ver: Importación de valores predeterminados )
Parece que los dos enfoques son diferentes y fundamentalmente incompatibles.
¿Por qué ambos funcionan?
Consulte el código fuente y explique el mecanismo... Estoy interesado en entender cómo funciona esto.
Actualizar
Esto no es un duplicado de ¿Cuál es la diferencia entre importar * como reaccionar de 'reaccionar' frente a importar reaccionar de 'reaccionar'
Esa pregunta fue respondida con información general del módulo ES6.
Estoy preguntando sobre el mecanismo que hace que el módulo de react
funcione así. Parece estar relacionado con el mecanismo de exportación "hacky" en la fuente aquí , pero no está claro cómo eso permite importar el módulo completo y solo la exportación predeterminada a React
y hacer que ambos enfoques funcionen con la transpilación de JSX, etc.
De hecho, las declaraciones de importación de ES import import default
e import *
no son lo mismo, el hecho de que se comporten de la misma manera en este caso es una combinación de cómo los autores de React eligieron publicar la biblioteca y las capas de compatibilidad en TypeScript (usando esModuleInterop
) o Babel y su bundler para que "simplemente funcionen". Probablemente no debería funcionar de acuerdo con las especificaciones de ES6, pero hoy todavía estamos trabajando en una era en la que los módulos JS son un desastre, por lo que herramientas como Babel, TypeScript, Webpack, etc. intentan normalizar el comportamiento.
React no es una biblioteca ES6. Si observa el código fuente , verá esto en index.js
:
const React = require('./src/React'); // TODO: decide on the top-level export form. // This is hacky but makes it work with both Rollup and Jest. module.exports = React.default || React;
(Tenga en cuenta el comentario, incluso en el código fuente de React tienen problemas con la compatibilidad de exportación predeterminada de ES6).
La sintaxis module.exports =
es CommonJS (NodeJS). Un navegador no entendería esto. Es por eso que usamos paquetes como Webpack, Rollup o Parcel. Entienden todo tipo de sintaxis de módulos y producen paquetes que deberían funcionar en el navegador.
Pero aunque React no es una biblioteca de ES, tanto TypeScript como Babel le permiten importarlo como si lo fuera (usando la sintaxis de import
, en lugar de require()
, etc.), pero hay diferencias entre CJS y ES que deben resolverse. Uno de ellos es el hecho de que export =
puede brindarle cosas que ES no tiene una forma de importar que cumpla con las especificaciones, como una función o una clase como módulo. Para solucionar estas incompatibilidades, Babel le ha permitido durante un tiempo importar módulos CJS como si estuvieran exportando algo de forma predeterminada, o importarlos como un espacio de nombres. TypeScript por un tiempo no hizo esto, pero más recientemente lo agregó como una opción en esModuleInterop
. Así que ahora tanto Babel como TypeScript pueden permitir que un módulo CJS se importe de manera bastante consistente utilizando importaciones ES predeterminadas o de espacio de nombres.
Con TypeScript también depende de cómo se definan realmente las definiciones de tipo para la biblioteca. No entraré en eso, pero puede imaginar situaciones en las que, gracias a transpilers y bundlers, una importación particular funciona en tiempo de ejecución , pero TypeScript no se compila sin errores.
Otra cosa que vale la pena mencionar es que si observa el código creado para React, hay una versión del módulo UMD , así como la versión CJS. La versión UMD incluye un código de tiempo de ejecución retorcido para intentar que funcione en cualquier entorno de módulo, incluido el navegador. Es principalmente para usar si solo desea incluir React en tiempo de ejecución (es decir, no usa un paquete). ejemplo
¿Confuso? Sí, eso creo. :)
Lo más probable es que tenga "allowSyntheticDefaultImports": true,
configurado en su tsconfig.json
, que esencialmente cierra el compilador sobre las importaciones predeterminadas que cree que no son válidas. Typescript agregó esModuleInterop
, que hace esencialmente lo que hace babel para cargar módulos.
Esto le permite utilizar las importaciones predeterminadas de ES6 incluso cuando el código fuente que está importando no exporta nada de forma predeterminada.
Typescript es estricto (sigue las reglas) cuando se trata de esto, por lo que requieren que import * as React from 'react'
. O requiere que le diga que permita importaciones predeterminadas sintéticas en su configuración base.