为什么未定义从index.tsx文件导出?(React+Typescript)



我有一个简单的上下文提供程序,我想将其导出为npm包。

我使用create-rect库创建了我的npm包。

我已经创建了一个index.tsx文件,当从另一个项目导入这个npm包时可以访问该文件;我正在将上下文提供程序导入此index.tsx,然后将其导出。

当我尝试使用从index.tsx导入的ContextProvider运行测试时,导入的对象是未定义的(即使我可以在VS代码中导航到它(。但是,当我直接从源代码导入它时,它工作得很好。我需要让它从index.tsx文件中工作,以便通过npm包访问它。

有人能向我解释一下我在这里缺了什么吗?

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/ErrorHandlerContentProvider.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运行测试

FAIL src/index.test.tsx●ErrorHandlerContentProvider›是真实的

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)

这似乎真的很可疑:

// src/index.test.tsx
// works
// import ErrorHandler from './contexts/ErrorHandlerContextProvider'
// does not work
import { ErrorHandler } from '.'

由于禁用的导入有效,我们知道impl文件的默认导出有效。但您的索引没有默认导出(这对npm来说似乎是不礼貌的,但您确实这样做了(。这告诉我要么测试文件错误地导入impl,要么桶文件错误地。(我认为索引不太可能是错误地导出impl。(

你方所有其他进口、出口和报关单经抽查似乎都是正确的。

因此,这里有一袋想法:

  • 尝试使用实际文件名,而不是仅使用from '.'
  • 桶中没有React,请尝试将index.tsx重命名为index.ts
  • 当涉及到默认文件扩展名时,请确认您的测试设置使用与应用程序代码相同的设置&默认文件名

如果这些都不起作用,请尝试使用您的基本错误捕获技能来确定链中第一个断开的链接。

  1. 在导入后将console.log("ErrorHandler", ErrorHandler)添加到索引中,然后再次运行测试并查找该日志语句,以确认导入的内容与您预期的一样
  2. 在测试文件中尝试同样的操作,检查从桶文件中导入的内容

目标是找出导入链的哪个步骤出错。


此外:ES6析构函数与ES6命名的导入/导出不是一回事,不能混合匹配。所以,我认为这个代码不应该工作:

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

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

原因是file1没有命名导出,它只有一个默认导出,并且file2中的import语句不允许在导入对象时破坏该对象;从文件1导入命名导出"属性"这将不起作用,因为file1没有命名导出。

老实说,我不认为这违反了规定,但这是需要记住的。


最后一个想法是:不要这样组织你的测试。

  1. ErrorHandlerContextProvider的测试文件应与提供程序的impl位于同一文件夹中(或根据您的喜好位于嵌套的__tests文件夹中(。该测试套件的正确工作是测试提供者的实际impl
  2. 如果您甚至为index.test.tsx而烦恼,那么该套件的正确工作就是来证明npm模块的公共API具有正确的形状。它没有测试实际功能的业务

即使没有必要解决问题,我也会进行此更改。但是,我会推迟做出改变,直到你确切地弄清楚根本问题是什么(并解决了它(。

最新更新