{"id":249,"date":"2026-06-10T21:03:47","date_gmt":"2026-06-10T20:03:47","guid":{"rendered":"https:\/\/zebra-north.com\/code\/?p=249"},"modified":"2026-06-10T21:03:47","modified_gmt":"2026-06-10T20:03:47","slug":"how-to-mock-overloaded-functions-in-jest-and-typescript","status":"publish","type":"post","link":"https:\/\/zebra-north.com\/code\/2026\/06\/10\/how-to-mock-overloaded-functions-in-jest-and-typescript\/","title":{"rendered":"How To Mock Overloaded Functions in Jest and TypeScript"},"content":{"rendered":"\n<p>To provide an implementation of a mock function you must know its function signature, but whichever one of the overloads you choose, TypeScript will give you an error. The fix is actually quite simple: use the signature of the actual implementation, not the overloads.<\/p>\n\n\n<a class=\"wp-block-read-more\" href=\"https:\/\/zebra-north.com\/code\/2026\/06\/10\/how-to-mock-overloaded-functions-in-jest-and-typescript\/\" target=\"_self\">Read more<span class=\"screen-reader-text\">: How To Mock Overloaded Functions in Jest and TypeScript<\/span><\/a>\n\n\n<p>Suppose you have a function <code>f()<\/code> with two overloads and an implementation. The two overloads appear first, and have no function body. The implementation appears last. It has a function body, but importantly, its signature does not take part in overload resolution. This means that <strong>it will be missing if all you have is a types.d.ts file<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">function f(x: number): void; \/\/ Overload 1.\nfunction f(x: string): void; \/\/ Overload 2.\n\n\/\/ Implementation.\nfunction f(x: number | string): void {\n    \/\/ ...\n}\n\n\/\/ Create a variable with the type of function `f()`&#039;s overload set.\nlet v = f;\nv = (x: number) =&gt; { }; \/\/ Error: Does not match overload 2.\nv = (x: string) =&gt; { }; \/\/ Error: Does not match overload 1.\n\n\/\/ The solution: match the actual implementation signature.\nv = (x: number | string) =&gt; { };<\/code><\/pre>\n\n\n\n<p>In the case above the solution is obvious, as the implementation&#8217;s function signature is visible. If you do not have the implementation function signature then unfortunately the TypeScript error message will not give it to you. Instead, you have to synthesize it yourself by taking the union of all the possible types of each parameter using the <code>|<\/code> operator.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Practical Example: Mocking http.get()<\/h2>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">import * as http from &#039;node:http&#039;;\n\n\/\/ Replace the http module with a mock implementation.\njest.mock(&#039;node:http&#039;);\n\n\/\/ Create an alias with the correct type, so that TypeScript knows we are working with a mock.\nconst MockHttp = http as jest.Mocked&lt;typeof http&gt;;\n\nconst myImplementation = function (url: string | URL, options: http.RequestOptions, callback: (res: http.IncomingMessage) =&gt; void)\n{\n    \/\/ ...\n}\n\n\/\/ Try to mock http.get(). Error.\nMockHttp.get.mockImplementation(myImplementation);\n<\/code><\/pre>\n\n\n\n<p>This will give you a lengthy error message telling you that your function signature is invalid, even though it matches the signature given in the documentation.  At this point you notice that <code>http.get()<\/code> actually has multiple signatures. None of them will work &#8211; you have to combine them together into one.<\/p>\n\n\n\n<p>Unfortunately the function signature of the actual implementation is not visible because it is internal to Node, however you can work it out for yourself. Look at the type definitions in <code>@types\/node\/http.d.ts<\/code> and combine them all together.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">\/\/ From node_modules\/@types\/node\/http.d.ts\nfunction get(options: RequestOptions | string | URL, callback?: (res: IncomingMessage) =&gt; void): ClientRequest;\nfunction get(url: string | URL, options: RequestOptions, callback?: (res: IncomingMessage) =&gt; void): ClientRequest;\n\n\/\/ The implementation must accept either of these signatures, therefore:\n\/\/ The first parameter is either &quot;options&quot; or &quot;url&quot;, so it is either string, URL, or RequestOptions.\n\/\/ The second parameter is either &quot;callback&quot; or &quot;options&quot;, so it is optional and accepts either a callback or RequestOptions\n\/\/ Only first overload has a third parameter, which is &quot;callback&quot;, so it is optional and accepts a callback.\n\/\/ Putting these together gives:\nfunction (\n    url: string | URL | RequestOptions,\n    options?: RequestOptions | ((res: IncomingMessage) =&gt; void),\n    callback?: (res: IncomingMessage) =&gt; void\n): ClientRequest;<\/code><\/pre>\n\n\n\n<p>Now you can create your implementation with that function signature and pass it through to <code>MockHttp.get.mockImplementation()<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-typescript\">import * as http from &#039;node:http&#039;;\n\n\/\/ Replace the http module with a mock implementation.\njest.mock(&#039;node:http&#039;);\n\n\/\/ Create an alias with the correct type, so that TypeScript knows we are working with a mock.\nconst MockHttp = http as jest.Mocked&lt;typeof http&gt;;\n\nconst myImplementation = function (url: string | URL | http.RequestOptions, options?: http.RequestOptions | ((res: http.IncomingMessage) =&gt; void), callback?: (res: http.IncomingMessage) =&gt; void)\n{\n    \/\/ ...\n}\n\n\/\/ Success!\nMockHttp.get.mockImplementation(myImplementation);\n<\/code><\/pre>\n\n\n\n<p>There are a few things to note when doing this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Combine types using <code>|<\/code>.<\/li>\n\n\n\n<li>Make the parameter optional with <code>?<\/code> if it is optional in any overload.<\/li>\n\n\n\n<li>Function signatures require an extra set of parentheses around them when used in combination with the <code>|<\/code> operator.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>To provide an implementation of a mock function you must know its function signature, but whichever one of the overloads you choose, TypeScript will give you an error. The fix is actually quite simple: use the signature of the actual implementation, not the overloads. Suppose you have a function f() with two overloads and an [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-249","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts\/249","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/comments?post=249"}],"version-history":[{"count":1,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts\/249\/revisions"}],"predecessor-version":[{"id":250,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts\/249\/revisions\/250"}],"wp:attachment":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/media?parent=249"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/categories?post=249"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/tags?post=249"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}