为 useHistory 钩子模拟 react-router-dom 会导致以下错误 - TS2698:传播类型只能从对象类型创建

wen*_*jun 13 typescript reactjs jestjs react-router react-hooks

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

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useHistory: () => ({
    location: {
      pathname: '/list',
    },
  }),
}));
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

"@types/jest": "^26.0.4",
"jest": "^26.1.0",
"ts-jest": "^26.1.1",
Run Code Online (Sandbox Code Playgroud)

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

Est*_*ask 23

jest.requireActual返回unknown无法传播的类型。

正确的类型是:

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

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom') as typeof ReactRouterDom,
  useHistory: ...,
}));
Run Code Online (Sandbox Code Playgroud)

一个快速的解决方法是any

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom') as any,
  useHistory: ...,
}));
Run Code Online (Sandbox Code Playgroud)

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

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

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom') as any,
  __esModule: true,
  useHistory: ...,
}));
Run Code Online (Sandbox Code Playgroud)

  • `requireActual` [是通用的](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/9c680c4/types/jest/index.d.ts#L184-L189),所以替代方案是:`...jest。 requireActual<typeof ReactRouterDom>("react-router-dom")`。 (5认同)
  • 还要补充一点,对于那些使用默认推荐的 eslint 设置的人,您需要在 `ReactRouterDom` 类型上方添加 `// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion`断言,尽管 eslint 告诉我们不需要断言类型。 (2认同)