为 useHistory 钩子模拟 react-router-dom 会导致以下错误 - TS2698: Spread types may only be created from object ty

Posted

技术标签:

【中文标题】为 useHistory 钩子模拟 react-router-dom 会导致以下错误 - TS2698: Spread types may only be created from object types【英文标题】:Mocking react-router-dom for useHistory hook causes the following error - TS2698: Spread types may only be created from object types 【发布时间】:2020-10-27 16:35:46 【问题描述】:

我试图在我的一个测试用例中模拟react-router-dom,以便useHistory 挂钩将在我的测试中起作用。我决定使用jest.mock 来模拟整个模块,并使用jest.requireActual 来保留我可能不想模拟的其他属性。

jest.mock('react-router-dom', () => (
  ...jest.requireActual('react-router-dom'),
  useHistory: () => (
    location: 
      pathname: '/list',
    ,
  ),
));

这实际上源自对以下问题的高度评价的解决方案之一:How to mock useHistory hook in jest?

但是,TypeScript 编译器在以下行标记以下错误 ...jest.requireActual('react-router-dom'),

TS2698:传播类型只能从对象类型创建。

有趣的是,我只有在将 jest 和 ts-jest 更新到最新版本(jest v26)后才会遇到这个问题。我在使用 jest 24.x.x 时没有遇到任何这些问题。

"@types/jest": "^26.0.4",
"jest": "^26.1.0",
"ts-jest": "^26.1.1",

有人知道如何为最新的 jest 版本解决这个问题吗?

【问题讨论】:

jest.requireActual('react-router-dom') 返回了什么? 应该是“react-router-dom”包中的其他属性/方法?我这样做的目的是只模拟 useHistory 钩子,而不是整个包。 【参考方案1】:

jest.requireActual 返回的unknown 类型不能传播。

正确的类型是:

import * as ReactRouterDom from 'react-router-dom';

jest.mock('react-router-dom', () => (
  ...jest.requireActual('react-router-dom') as typeof ReactRouterDom,
  useHistory: ...,
));

快速解决方法是any

jest.mock('react-router-dom', () => (
  ...jest.requireActual('react-router-dom') as any,
  useHistory: ...,
));

这是可以接受的,因为在这种情况下它不会损害类型安全。

由于react-router-dom是ES模块,更正确的模拟方式是:

jest.mock('react-router-dom', () => (
  ...jest.requireActual('react-router-dom') as any,
  __esModule: true,
  useHistory: ...,
));

【讨论】:

谢谢!这解决了我的问题。知道为什么这个错误只会出现在 jest 26 上吗? 另外一点要补充的是,对于那些使用默认推荐的eslint设置的人,你需要在ReactRouterDom类型断言之上添加// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion,尽管eslint告诉我们不需要断言类型。 可能您使用了没有此行为的旧 TS 版本,或者使用了具有不同类型的另一个 Jest 设置,还有第三方 @types/jest。没错,我总是默认禁用此规则。 requireActual is generic,所以另一种选择是:...jest.requireActual<typeof ReactRouterDom>("react-router-dom") 我可以确认@JonathanReyes 的解决方案同样有效 :)

以上是关于为 useHistory 钩子模拟 react-router-dom 会导致以下错误 - TS2698: Spread types may only be created from object ty的主要内容,如果未能解决你的问题,请参考以下文章

useHistory react-router-dom 无效的钩子调用

如何在类组件类型脚本中使用 useHistory() 钩子

模拟 useHistory 并期望 toBeCalledWith

如何在初始渲染后重新渲染自定义钩子

使用 useHistory 重定向页面并在单击为 false 时删除图像

如何测试/模拟反应钩子?