Búsqueda de sitios web

javascript - ¿Por qué la exportación del archivo index.tsx es indefinida? (React + Typescript)


Tengo un proveedor de contexto simple que quiero exportar como un paquete npm.

Creé mi paquete de npm usando create-react-library.

He creado un archivo index.tsx que será accesible al importar este paquete npm desde otro proyecto; estoy importando el Proveedor de Contexto a este index.tsx y luego exportándolo.

Cuando intento ejecutar una prueba con el ContextProvider importado desde index.tsx, el objeto importado es undefined (aunque puedo navegar hasta él en VS Code). Sin embargo, cuando lo importo directamente desde la fuente, funciona bien. Necesitaré que funcione desde el archivo index.tsx para poder acceder a él a través del paquete npm.

¿Alguien puede explicarme qué me estoy perdiendo aquí?

src/index.tsx

import ErrorHandler from './contexts/ErrorHandlerContextProvider'

export { ErrorHandler }

// export { default as ErrorHandler } from './contexts/ErrorHandlerContextProvider' //<-- no luck

src/index.test.tsx

// import ErrorHandler from './contexts/ErrorHandlerContextProvider' // <-- this import works
import { ErrorHandler } from '.'

describe('ErrorHandlerContextProvider', () => {
  it('is truthy', () => {
    expect(ErrorHandler.ErrorHandlerContextProvider).toBeTruthy()
  })
})

src/contexts/ErrorHandlerContextProvider.tsx

import React, { createContext, FC, useContext } from 'react'
import PropTypes from 'prop-types'

type errorHandlerContextType = {
  handleError: (error: Error, info: string) => Promise<void>
}

const ErrorHandlerContext = createContext<errorHandlerContextType | null>(null)

const useErrorHandlerContextProvider = () => {
  return useContext(ErrorHandlerContext)
}

const ErrorHandlerContextProvider: FC = ({ children }) => {

  const handleError = (error: Error, info: string): Promise<void> => {
    console.log('error', error)
    console.log('info', info)

    return Promise.reject(error)
  }

  return (
    <ErrorHandlerContext.Provider value={{ handleError }}>
      {children}
    </ErrorHandlerContext.Provider>
  )
}

ErrorHandlerContextProvider.propTypes = {
  children: PropTypes.node.isRequired
}

export default { ErrorHandlerContextProvider, useErrorHandlerContextProvider }

/tsconfig.json

{
  "compilerOptions": {
    "outDir": "dist",
    "module": "esnext",
    "lib": ["dom", "esnext"],
    "moduleResolution": "node",
    "jsx": "react",
    "sourceMap": true,
    "declaration": true,
    "esModuleInterop": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "allowSyntheticDefaultImports": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist", "example"]
}

npm run test

FALLA src/index.test.tsx ● ErrorHandlerContextProvider › es verdadero

TypeError: Cannot read property 'ErrorHandlerContextProvider' of undefined

  4 | describe('ErrorHandlerContextProvider', () => {
  5 |   it('is truthy', () => {
> 6 |     expect(ErrorHandler.ErrorHandlerContextProvider).toBeTruthy()
    |                         ^
  7 |   })
  8 | })
  9 |

  at Object.<anonymous> (src/index.test.tsx:6:25)

Respuesta #1

Esto parece realmente sospechoso:

// src/index.test.tsx

// works
// import ErrorHandler from './contexts/ErrorHandlerContextProvider'

// does not work
import { ErrorHandler } from '.'

Dado que la importación deshabilitada funciona, sabemos que la exportación por defecto del archivo impl está funcionando. Pero tu índice no tiene una exportación por defecto (lo cual parece mala educación para npm, pero tú haces lo tuyo). Esto me dice que o bien el archivo de prueba está importando el impl de manera incorrecta, o el archivo barril lo está haciendo mal. (Creo que es poco probable que el índice esté exportando el impl de manera incorrecta.)

Todas sus demás importaciones, exportaciones y declaraciones parecen correctas a simple vista.

Así que aquí hay una bolsa de ideas:

  • Intenta usar el nombre de archivo real en lugar de solo from '.'
  • El archivo de barril no tiene React, así que intenta renombrar index.tsx a index.ts
  • Confirma que la configuración de tu prueba utiliza los mismos ajustes que el código de la aplicación en lo que respecta a las extensiones de archivo predeterminadas y los nombres de archivo predeterminados

Si ninguno de esos funciona, intenta usar tus habilidades básicas de detección de errores para localizar el primer eslabón roto en la cadena.

  1. Agrega console.log("ErrorHandler", ErrorHandler) a tu índice después de la importación, luego ejecuta las pruebas nuevamente y busca esa declaración de registro para confirmar que lo importado se ve como esperarías.
  2. Intenta lo mismo dentro del archivo de prueba, para examinar qué se importa desde el archivo barril.

El objetivo es averiguar en qué paso de la cadena de importación las cosas salen mal.


También: la desestructuración de ES6 no es lo mismo que las importaciones/exportaciones con nombre de ES6, y no se pueden mezclar. Así que, creo que este código no debería funcionar:

// file1.js
export default { property: 'value' }


// file2.js
import { property } from './file1' // should fail

La razón es que file1 no tiene exportaciones nombradas, solo tiene una exportación por defecto, y la declaración de importación en file2 no está permitida para desestructurar ese objeto al importarlo. El código en file2 debería leerse como: "importar exportación nombrada 'propiedad' desde file1" -- lo cual no funcionará porque file1 no tiene exportaciones nombradas.

Con toda honestidad, no veo una violación de esto aquí, pero es algo a tener en cuenta.


Un pensamiento final: no organices tus pruebas de esta manera.

  1. El archivo de prueba para ErrorHandlerContextProvider debería vivir en la misma carpeta que la implementación del proveedor (o en una carpeta anidada __tests, según tu preferencia). El trabajo adecuado de ese conjunto de pruebas es probar la implementación real del proveedor.
  2. Si siquiera te molestaras en crear un index.test.tsx, el trabajo adecuado de ese conjunto es simplemente demostrar que la API pública de tu módulo de npm tiene la forma correcta. No tiene nada que ver probar la funcionalidad real.

Haría este cambio incluso si no es necesario para solucionar el problema. Pero, esperaría para hacer el cambio hasta después de que hayas descubierto exactamente cuál es el problema subyacente (y lo hayas solucionado).

Artículos relacionados