简体   繁体   中英

Jest mocking TypeScript class "No overload expects 1 type arguments"

I'm trying to mock a TypeScript class with Jest and I'm obviously doing something because receive the following error:

error TS2743: No overload expects 1 type arguments, but overloads do exist that expect either 0 or 2 type arguments.

This is my code:

Foo.ts

export default class Foo {
  bar(): number {
    return Math.random()
  }
}

Foo.test.ts

import Foo from './Foo'

describe('Foo', () => {
  it("should pass", () => {
    const MockFoo = jest.fn<Foo>(() => ({
      bar: jest.fn(() => {
        return 123
      }),
    }))
  })
})

The full error:

TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
src/Foo.test.ts:6:29 - error TS2743: No overload expects 1 type arguments, but overloads do exist that expect either 0 or 2 type arguments.

6     const MockFoo = jest.fn<Foo>(() => ({
                              ~~~

UPDATE

If it is of any relevance, this is my Jest config:

module.exports = {
  moduleFileExtensions: ['ts', 'js'],
  transform: {
    '^.+\\.ts$': 'ts-jest',
  },
  testMatch: ['**/src/**/*.test.(ts)'],
  testEnvironment: 'node',
};

Jest has the following signature for jest.fn:

/**
 * Creates a mock function. Optionally takes a mock implementation.
 */
function fn<T, Y extends any[]>(implementation?: (...args: Y) => T): Mock<T, Y>;

So you need to specify the array of types for the args, in your particular case you could just pass an empty array as there are no args in your implementation function.

const MockFoo = jest.fn<Foo, []>(() => ({

You can use the ts-jest 's mocked() function:

This is all type safe and compiles without warnings in TypeScript:

import Foo from './Foo'
import {mocked} from 'ts-jest/utils'

function argIsFoo(foo : Foo) {
    ; // do nothing
}

describe('Foo', () => {
    it("should pass", () => {
        const mockFoo = mocked({
            bar: jest.fn(() => {
                return 123
            })
        });

        // mockFoo is compatible with Foo class
        argIsFoo(mockFoo);

        // method has the right type
        expect(mockFoo.bar()).toEqual(123);

        // can use the mock in expectations
        expect(mockFoo.bar).toHaveBeenCalled();

        // is type safe access method as a mock
        expect(mockFoo.bar.mock.calls.length).toEqual(1);
    });
});

If you only want to mock out some of Foo's methods, then in mocked() you need to cast your mock object with as unknown as Foo :

import {mocked} from 'ts-jest/utils'

class Foo {
    bar(): number {
        return Math.random();
    }
    dontMockMe(): string {
        return "buzz";
    }
}

function argIsFoo(foo : Foo) {
    ; // do nothing
}

describe('Foo', () => {
    it("should pass", () => {
        const mockFoo = mocked({
            bar: jest.fn(() => {
                return 123
            })
        } as unknown as Foo);

        // mockFoo is compatible with Foo class
        argIsFoo(mockFoo);

        // method has the right type
        expect(mockFoo.bar()).toEqual(123);

        // can use the mock in expectations
        expect(mockFoo.bar).toHaveBeenCalled();

        // is type safe access method as a mock
        expect(mockFoo.bar.mock.calls.length).toEqual(1);
    });
});

As it turns out, it's possible to have the TypeScript compiler ignore errors like this by turning off diagnostics [1].

// jest.config.js
module.exports = {
  // [...]
  globals: {
    'ts-jest': {
      diagnostics: false
    }
  }
};

However, it's currently unclear to me what other implications this might have.

[1] https://huafu.github.io/ts-jest/user/config/diagnostics#enabling-diagnostics-for-test-files-only

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM