Short Answer

The global spyOn(...) function returns a jasmine.Spy not a jest.SpyInstance. The reason for this, as far as I can tell, is to ease migration from Jasmine to Jest.

Here are two options:

let barSpy: jest.SpyInstance;
barSpy = jest.spyOn(a, 'bar'); // <--- explicitly use jest.spyOn

// or

let barSpy: jasmine.Spy; // <--- use jasmine.Spy as your type
barSpy = spyOn(a, 'bar');

Further Explanation

The node_modules\@types\jest\index.d.ts file has the Jest type definitions. By looking at them, we can see the two implementations of spyOn.

  • The spyOn that returns a jest.SpyInstance is inside the jest namespace.
  • The spyOn that returns a jasmine.Spy is in the global namespace.

Unless you're in the process of migrating from Jasmine to Jest, I would use the jest.spyOn function instead of the global one.

Answer from Shaun Luttin on Stack Overflow
๐ŸŒ
DEV Community
dev.to โ€บ lausuarez02 โ€บ jest-spyon-and-typescript-1a58
Jest 'spyOn' and typeScript - DEV Community
March 26, 2023 - If you been coding with typescript and want to use 'spyOn' on your test you would have to type it...
๐ŸŒ
Jest
jestjs.io โ€บ mock functions
Mock Functions ยท Jest
1 week ago - Mock functions are also known as "spies", because they let you spy on the behavior of a function that is called indirectly by some other code, rather than only testing the output.
Discussions

jestjs - Jest spyOn not working with typescript: "Property 'mockRestore' is missing in type 'Spy'" - Stack Overflow
When using spyOn with jest and typescript I am getting this type error: Type 'Spy' is not assignable to type 'SpyInstance '. Property 'mockRestore' is missing in type 'Spy'. Here is a code More on stackoverflow.com
๐ŸŒ stackoverflow.com
jestjs - TypeScript+Jest - how to use jest.spyOn with generic TypeScript methods? - Stack Overflow
Has anyone been able to apply jest.spyOn correctly with generics to help with this issue? More on stackoverflow.com
๐ŸŒ stackoverflow.com
[deleted by user]
The problem with the second is that you can't reset the mock behavior, in case you need to. More on reddit.com
๐ŸŒ r/typescript
2
0
April 14, 2024
jest.spyOn does not work when compared ts-jest
Problem Doesn't work test when another function is called inside function. But this works with ts-jest. I understand that can do the same by injecting it as a callback function. index.ts export con... More on github.com
๐ŸŒ github.com
11
November 1, 2021
๐ŸŒ
Jest
jestjs.io โ€บ the jest object
The Jest Object ยท Jest
1 week ago - Since Jest 22.1.0+, the jest.spyOn method takes an optional third argument of accessType that can be either 'get' or 'set', which proves to be useful when you want to spy on a getter or a setter, respectively.
๐ŸŒ
Medium
medium.com โ€บ @vivek.murarka โ€บ mocking-with-jest-in-typescript-javascript-d203699cc617
Mocking with Jest in Typescript/Javascript | by Vivek Murarka | Medium
August 8, 2023 - import adminMock from "admin"; const mockAuth = {} as unknown as adminMock.auth.Auth; describe(" testAuthorisation",() =>{ it("test authorisation withod using admin library", async() =>{ mockAuth.verifyIdToken = jest.fn(mockRejectedIdToken); //spy on auth method of admin, and mock the impelementation to mockAuth jest.spyOn(adminMock, "auth").mockImplementation(() => mockAuth); }); });
๐ŸŒ
Domenico Luciani
domenicoluciani.com โ€บ 2022 โ€บ 06 โ€บ 17 โ€บ how-to-mock-with-jest-typescript.html
How to mock with Jest and Typescript ยท Domenico Luciani
June 17, 2022 - Simple and clean, essentially we are spying on our dependency, specifically on the publishMessage method and then asserting that it receives hello as parameter. Of course we can always program the mocked dependency behaviour since the jest.spyOn method returns a Jest mock ๐Ÿ‹๐Ÿปโ€โ™‚๏ธ
๐ŸŒ
DEV Community
dev.to โ€บ qmenoret โ€บ mocks-and-spies-with-jest-32gf
Mocks and Spies with Jest - DEV Community
December 31, 2020 - describe('my test', () => { beforeEach(() => { jest.restoreAllMocks() }) it('calls the right route', async () => { jest.spyOn(global, 'fetch').mockReturnValue({}) await getUser(id) expect(global.fetch).toHaveBeenCalledWith('/users/12') }) }
๐ŸŒ
Carl Rippon
carlrippon.com โ€บ how-to-mock-a-function-in-jest-with-typescript
How to mock a function in Jest for a React and Typescript app
January 14, 2022 - const mock = jest.spyOn(data, "getCharacter").mockResolvedValue("Bob"); ... The code from this post is available in Codesandbox in the link below. ... A comprehensive guide to building modern React applications with TypeScript. Learn best practices, advanced patterns, and real-world development techniques.
Find elsewhere
๐ŸŒ
Webdevtutor
webdevtutor.net โ€บ blog โ€บ typescript-jest-spyon
Mastering TypeScript Jest SpyOn: A Complete Guide
Let's take a look at a simple example to understand how to use SpyOn in TypeScript: // app.ts export function add(a: number, b: number): number { return a + b; } // app.test.ts import { add } from './app'; test('should spy on add function', () => { const spy = jest.spyOn(console, 'log'); add(2, 3); expect(spy).toHaveBeenCalledWith(5); });
Top answer
1 of 2
1

I think all you're missing is the word async in your call to mockImplementationOnce(). Then you can remove the type params for jest.spyOn. You don't get type safety within your mock implementation automatically, but if you're really worried about it, you can add as HttpResponse<FeatureFlag>.

let result: FetchResponse<boolean, string>;

describe('getFeatureFlag', () => {
    beforeEach(async () => {
        //                                                  missing
        //                                                     โ†“
        jest.spyOn(HttpClient, 'get').mockImplementationOnce(async () => ({
            ok: true,
            data: {
                toggleActive: true,
            },
        } as HttpResponse<FeatureFlag>));

        result = await getFeatureFlag(flagName);
    })
});

TS Playground

Granted, this doesn't answer the question asked in the title, but it should fix your code. I messed around for a long time trying to get your specified generic type arguments to work, and eventually gave up. It may be a limitation of the declarations in the jest namespace.

2 of 2
0

Could you try to change your code like this:

jest.spyOn(HttpClient.prototype, 'get').mockImplementationOnce(() => {... return <expectedResultObject>; })

This works for me with the typed-rest-client/RestClient npm package just like charm:

import * as rm from 'typed-rest-client/RestClient';
import {StatusCodes} from 'http-status-codes';

let apiSpy: jest.SpyInstance;

apiSpy = jest.spyOn(rm.RestClient.prototype, 'get');
apiSpy.mockImplementation(path => {
    const response: rm.IRestResponse<string> = {
        statusCode: StatusCodes.OK,
        headers: {},
        result: 'stringResult'
    }
    return response;
})
๐ŸŒ
Salto.io
salto.io โ€บ blog-posts โ€บ typescript-unit-testing-pitfalls-with-jest-and-how-to-work-around-them
Typescript unit testing pitfalls with Jest
March 17, 2025 - When we encounter such an error, but still want to use spyOn we can do one of two things: 1. We can import the function from the "internal" file that exported it in the first place instead of mocking it through the index.ts file, by changing our import to: This is not ideal as it requires a more intimate knowledge of the file structure, but this might be ok for tests that are so coupled with the implementation anyway. 2. We can mock the whole package and use jest.requireActual to avoid mocking the other functions and to also preserve the original implementation:
๐ŸŒ
Reddit
reddit.com โ€บ r/typescript โ€บ [deleted by user]
Doubt about Jest.spyOn and Typescript
April 14, 2024 - You are giving spy the type SpyInstance<any, any>, which will probably lead to confusion. Example: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/168988c84f9e825dd6a7d625eb605502b0b36c97/types/jest/jest-tests.ts#L686 ... TypeScript is a language for application-scale JavaScript development.
๐ŸŒ
DEV Community
dev.to โ€บ devin-rosario โ€บ complete-guide-to-jestspyon-for-unit-testing-4io6
Complete Guide to Jest.spyOn for Unit Testing - DEV Community
October 16, 2025 - 7. Enable Jest 30 explicit resource management Use using keyword for automatic cleanup. Requires Node 20+ and TypeScript 5.2+. Jest.spyOn is precise surgical tool. Not sledgehammer. Use when need to verify method calls without replacing implementation. Always restore.
๐ŸŒ
Webdevtutor
webdevtutor.net โ€บ blog โ€บ typescript-jest-spyon-type
Mastering TypeScript Jest spyOn Type: A Comprehensive Guide
In this guide, we will explore different scenarios and examples to help you master the spyOn type in TypeScript. The spyOn type in Jest allows you to create a spy function that tracks calls to another function without affecting its behavior.
๐ŸŒ
Xjavascript
xjavascript.com โ€บ blog โ€บ jest-spyinstance-typescript
Mastering Jest SpyInstance with TypeScript | XJavaScript.com
June 17, 2025 - When using SpyInstance in TypeScript, you can ensure that the functions you are spying on have the correct types. This helps catch type-related errors early in the development process and makes your tests more reliable. In Jest, you can create a SpyInstance in several ways.
๐ŸŒ
GitHub
github.com โ€บ swc-project โ€บ swc โ€บ issues โ€บ 3843
jest.spyOn does not work when compared ts-jest ยท Issue #3843 ยท swc-project/swc
November 1, 2021 - import * as index from '.'; describe('index', () => { it('called', () => { const spiedChild = jest.spyOn(index, 'child'); index.callChild(); expect(spiedChild).toHaveBeenCalled(); }); }); module.exports = { clearMocks: true, coverageDirectory: 'coverage', coverageProvider: 'v8', preset: 'ts-jest', clearMocks: true, testEnvironment: 'node', roots: ['<rootDir>/src/'], moduleFileExtensions: ['ts', 'js'], collectCoverageFrom: ['src/**/*.{ts,js}'], testPathIgnorePatterns: ['<rootDir>[/\\\\](node_modules|dist)[/\\\\]'], watchPlugins: [ 'jest-watch-typeahead/filename', 'jest-watch-typeahead/testname', ], silent: false, }; > jest console.log Hello World!
Author ย  Lycolia
๐ŸŒ
Webdevtutor
webdevtutor.net โ€บ blog โ€บ typescript-jest-spyon-private-method
Testing Private Methods in TypeScript with Jest spyOn
When writing unit tests for TypeScript code, it's common to come across scenarios where you need to test private methods. However, since private methods are not directly accessible outside the class, testing them can be a bit tricky. In this guide, we will explore how to use Jest's spyOn function ...
๐ŸŒ
Webdevtutor
webdevtutor.net โ€บ blog โ€บ typescript-spyon-function
Mastering TypeScript's SpyOn Function for Efficient Unit Testing
SpyOn is a built-in feature within TypeScript's Jest testing framework. Its primary purpose is to create a mock function that can be used as a substitute for an original function.
๐ŸŒ
Medium
mdpuneethreddy.medium.com โ€บ jest-mock-functions-or-modules-using-typescript-99711d69a3bb
Jest: Mock functions or modules using typescript | by M D PUNEETH REDDY | Medium
July 22, 2022 - import * as utils from "../utils" describe("mock tests",()=>{ jest.spyOn(utils,"getNumber").mockReturnValueOnce(1) it("mock function inside another function",()=>{ expect(utils.printNumber()).toBe(1) }) })
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 71115777 โ€บ how-can-i-set-correctly-types-on-jest-spyon
typescript - How can I set correctly types on jest.spyOn? - Stack Overflow
February 14, 2022 - I don't find a way on how to improve the following, narrowing any to a more precise type : .spyOn<MyParentClass, any> ... function jest.spyOn<T extends {}, M extends jest.NonFunctionPropertyNames<Required<T>>>(object: T, method: M, accessType: "get"): jest.SpyInstance<Required<T>[M], []> (+3 overloads)