Home » Web » Jest » Strongly Typed Mock with TypeScript and Jest

Strongly Typed Mock with TypeScript and Jest

TypeScript strongly typed nature help reducing the number of tests but unit tests will always be needed to test logic. Jest comes for free when using the React ecosystem and the project “create-react-app” which is also available with TypeScript as the transpiler. In this article, we will see a way to mock an interface that got injected into a class in a strongly typed fashion.

Before getting too far into the detail of the implementation, here is a basic interface that a class use in the application and a class that uses that interface by injection to another class. The goal will be to unit test the class that receives the injected interface. We want to abstract the implementation of the concrete injected class and rely on mocking the interface with Jest.

interface IClassToInject {
    run(): boolean;
class ClassToInject implements IClassToInject {
    public run(): boolean {
        return Math.random() >= 0.5;
class ClassToTest {
    constructor(private injectedClass: IClassToInject) { }

const myClass = new ClassToTest(new ClassToInject());

The idea will be to use jest.Mock which is generic. The problem that we want to have Jest using the same object but not the real type. The idea is to have Jest using the same structure but with the type swapped to use Jest’s stub. TypeScript type mapping can be handy in a situation where we want to preserve the structure but change the type. The type, that I called “Mockify” allows doing exactly this transformation for you. Instead of injecting the interface directly, we inject the Mockify interface. Creating a Mockify version force the definition of each property which you can set to jest.fn(). There is a little of boilerplate that could be automated but overall, the idea is to have the strongly typed nature available. If the interface adds a new member, delete, or rename, the transpiler will raise an error in your test! The notification brings extra validation very soon in the development flow.

The next step is to create a variable that will hold the mocked interface where you can set returned value depending on what is tested in each test. Finally, we set the mock object to the class by injecting the mock by the constructor.

type Mockify<T> = {
    [P in keyof T]: jest.Mock<{}>;
let mockInterfaceToInject: Mockify<IClassToInject> = {
    run: jest.fn()

const classToTest = new ClassToTest(mockInterfaceToInject);

In this article, we saw that it’s possible to keep an existing interface and to map its structure with new returned values that are from Jest’s mocking framework. It allows keeping in sync with the model and flexible by adding testing capability like giving returned value or count how many time a property is called.

If you like my article, think to buy my annual book, professionally edited by a proofreader. directly from me or on Amazon. I also wrote a TypeScript book called Holistic TypeScript

8 Responses so far.

  1. Éric Papa says:

    Thank you Mr. Desjardins. We were actually using Jasmine, but now thinking about switching to Jest!

  2. SAiNT_GLiTCH says:

    The only thing is you’ll have to stub out every method in this interface. If you have a huge interface it could be a pain, do you have an idea of how to automate this? The workaround I have is:

    interface Cat {
    name: string;
    favoriteFood: string;
    meow(): void;
    isHungry(): boolean;

    test(‘Stub out only a few attributes and mock ‘, () => {
    const MockableCat = jest.fn(() => ({
    name: ‘Butters’,
    meow: jest.fn()

    const mockedCat = new MockableCat();


    • You do not have to stub or mock all the interface but only the method you are asserting or that you want to avoid behind executed which should be very limited if your interfaces are well divided.

  3. Jo says:

    Thanks for that article. I’d like to use this to base my mocks on only interfaces but unfortunately I got following compiler error:

    “Argument of type ‘Mockify’ is not assignable to parameter of type ‘IClassToInject’. Types of property ‘run’ are incompatible. Type ‘Mock’ is not assignable to type ‘() => boolean’. Type ‘{}’ is not assignable to type ‘boolean’.”

    • Justin says:

      I’m having the same issue.
      It’s not clear to me how the ‘mockInterfaceToInject’ object is assigned the ‘IClassToInject’ type

      • Mike says:

        Same here, this is not working properly, unfortunately. I’m trying to mock. response object:

        const mStatusCode = 404
        const mBody = “Not found”
        let members = {
        body: mBody,
        statusCode: mStatusCode
        type Mockify = {
        [P in keyof T]: jest.Mock;

        let mockedResponse: Mockify = members;

        I’m getting errors because my `members` object does not mock everything in the Response interface, and I’m getting Justin’s error about typing when trying to use the mocked object.

        Too bad because it’s a nice idea….

  4. I wrote a library that pretty much works on the same premise that you are using here. It auto mocks interfaces so you only need to do

    const mockObj = mock();

    You can check it out here – https://github.com/marchaos/jest-mock-extended

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.