Type-Safe Mocking with Jest in TypeScript: Solving the 'Property mock does not exist on type' Error

Dec 08, 2025 · Programming · 14 views · 7.8

Keywords: TypeScript | Jest | Mocking

Abstract: This article addresses type safety issues when using Jest for unit testing in TypeScript environments. A common error, 'Property mock does not exist on type', occurs when accessing the .mock property of mocked functions. The article presents two solutions: using jest.spyOn with mockImplementation to maintain type safety, and employing jest.MockedFunction for type casting. Through practical code examples and detailed explanations, it helps developers perform efficient mocking tests while preserving TypeScript's type checking capabilities.

Problem Description

When using Jest for unit testing, developers often need to mock object methods to inspect their invocation behavior. In JavaScript, mock functions created via jest.fn() have a .mock property for accessing call records, arguments, and other details. For example:

test('not working', () => {
    const foo = new Foo();
    foo.addListener = jest.fn();
    foo.func(); // calls addListener with a callback
    const callback = foo.addListener.mock.calls[0][0];
    expect(callback()).toEqual(1);
});

However, when migrating this test to TypeScript, the compiler reports an error: error TS2339: Property 'mock' does not exist on type '(callback: () => number) => void'. This occurs because TypeScript's type system cannot infer that the function returned by jest.fn() includes the .mock property. Using any type assertions can resolve the error but sacrifices type safety.

Solution One: Using jest.spyOn with mockImplementation

To maintain type safety in TypeScript, the jest.spyOn method can be employed. jest.spyOn allows developers to spy on existing object methods while adding Jest's mocking capabilities and preserving the original type. Here is a complete example:

class Foo {
  addListener = (callback: () => number) => { }
  func = () => {
    this.addListener(() => 1);
  }
}

test('working', () => {
  const foo = new Foo();
  const mockAddListener = jest.spyOn(foo, 'addListener');
  mockAddListener.mockImplementation(() => { });
  foo.func();
  const callback = mockAddListener.mock.calls[0][0];
  expect(callback()).toEqual(1);
});

In this example, jest.spyOn(foo, 'addListener') returns an object with the jest.Mock type, enabling safe access to the .mock property. The mockImplementation method is optional and used to replace the original method's implementation. Advantages of this approach include:

Solution Two: Using jest.MockedFunction

For more precise control over mock function types, jest.MockedFunction can be used. This is a utility type provided by Jest to convert ordinary function types into mock types that include the .mock property. For example:

const addListenerMock = addListener as jest.MockedFunction<typeof addListener>;

Alternatively, in earlier versions, the jest.Mock type assertion can be applied:

const callback = (foo.addListener as jest.Mock).mock.calls[0][0];

Benefits of using jest.MockedFunction include:

Comparison and Application Recommendations

In practice, the choice between these solutions depends on specific testing needs:

In summary, when using Jest for mocking tests in TypeScript, employing jest.spyOn or jest.MockedFunction effectively resolves the 'Property mock does not exist on type' error. These methods not only ensure type safety but also provide flexible testing capabilities, making unit tests more efficient and reliable.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.