typescript - 模拟类方法的 jest.fn() 自动类型

标签 typescript unit-testing jestjs eslint

我的项目是严格类型化的,有很多限制。假设我有一些带有两种方法的类。

class SomeClass {
  public someMethod(param1: string, param2: number): string {
    return `${param1}: ${param2}`;
  }
  public otherMethod(param3: string[]): boolean {
    return !!param3.length;
  }
}

我想模拟这两个函数,我通常会这样做:const mock = jest.fn()不幸的是,严格类型 + eslint 规则在很多地方都提示这种方法。几个例子:

const mock = jest.fn();
mock.mockReturnValue(34); // no return value error
mock.mock.calls[0][0]; // ESLint: Unsafe member access [0] on an any value.(@typescript-eslint/no-unsafe-member-access)

我可以明确提供类型:

const mock = jest.fn<string, [string, number]>();
mock.mockReturnValue(34); // TS2345: Argument of type '34' is not assignable to parameter of type 'string'
mock.mock.calls[0][0]; // ok

它可以工作,但很烦人(特别是如果我们更改函数签名等)

为了避免这种情况,我可以这样做:

const mock1 = jest.fn<ReturnType<SomeClass['someMethod']>, Parameters<SomeClass['someMethod']>>();
const mock2 = jest.fn<ReturnType<SomeClass['otherMethod']>, Parameters<SomeClass['otherMethod']>>();

mock1.mockReturnValue(34); // error, TS2345: Argument of type '34' is not assignable to parameter of type 'string'
mock1.mockReturnValue('34'); // ok
mock2.mock.calls[0][1]; // error, TS2493: Tuple type '[string[]]' of length '1' has no element at index '1'.
mock2.mock.calls[0][0]; // ok

这看起来更好,但我需要重复这个 ReturnType<SomeClass['someMethod']>, Parameters<SomeClass['someMethod']>很多,如果有一些自动功能就好了。

这就是我失败的地方,我尝试使用以下命令重现它:

const typedJestFn = <T, K extends keyof T>() => jest.fn<ReturnType<T[K]>, Parameters<T[K]>>();
const mock4 = typedJestFn<SomeClass, 'someMethod'>();

但它得到:

TS2344: Type 'T[K]' does not satisfy the constraint '(...args: any) => any'.
   Type 'T[keyof T]' is not assignable to type '(...args: any) => any'.
     Type 'T[string] | T[number] | T[symbol]' is not assignable to type '(...args: any) => any'.
       Type 'T[string]' is not assignable to type '(...args: any) => any'.

奇怪的是,mock4 本身按预期工作

附注:

    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,

最佳答案

问题中的问题是,首先我们创建一个通用类型 T,然后从该 T 中获取一个 key K。使用 T[K] 我们尝试访问可以是任何类型的成员(不受模板类型限制)。

因此,虽然很难从类中过滤函数(方法),但事实证明我们根本不需要它。我们只需要任何函数,T 可以只是一个函数。

这是我最终得到的解决方案:

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const typedJestFn = <T extends (...args: any) => any>() => jest.fn<ReturnType<T>, Parameters<T>>();

不太好,有any,但它不会以任何方式影响,它只是通知 T 应该是函数类型。

关于typescript - 模拟类方法的 jest.fn() 自动类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64171350/

相关文章:

java - 单元测试断言 TreeMap 中的对象顺序正确?

reactjs - 期望在 Jest 中包含一组值中的文本,带有 React 的 enzyme

angular - 如何处理( ionic 选择)确定按钮?

angular - "Error: Uncaught (in promise): TypeError: Cannot read property ' 长度 ' of undefined"

c++ - 使用 GTest 访问违规读取位置,无需任何复杂测试

javascript - 如何模拟 JSON 导入 Jest TypeScript

jestjs - 试图运行 jest 的 jest 版本不正确

javascript - RxJS:禁止在效果和史诗中使用不安全的捕获并请求嵌套

typescript - 刚要填写的必填字段的TS错误如何处理?

.net - NUnit 测试在 OpenCover 中失败