Zebra Codes

How To Mock Overloaded Functions in Jest and TypeScript

10th June, 2026

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.

Read more: How To Mock Overloaded Functions in Jest and TypeScript

Suppose you have a function f() 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 it will be missing if all you have is a types.d.ts file.

function f(x: number): void; // Overload 1.
function f(x: string): void; // Overload 2.

// Implementation.
function f(x: number | string): void {
    // ...
}

// Create a variable with the type of function `f()`'s overload set.
let v = f;
v = (x: number) => { }; // Error: Does not match overload 2.
v = (x: string) => { }; // Error: Does not match overload 1.

// The solution: match the actual implementation signature.
v = (x: number | string) => { };

In the case above the solution is obvious, as the implementation’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 | operator.

A Practical Example: Mocking http.get()

import * as http from 'node:http';

// Replace the http module with a mock implementation.
jest.mock('node:http');

// Create an alias with the correct type, so that TypeScript knows we are working with a mock.
const MockHttp = http as jest.Mocked<typeof http>;

const myImplementation = function (url: string | URL, options: http.RequestOptions, callback: (res: http.IncomingMessage) => void)
{
    // ...
}

// Try to mock http.get(). Error.
MockHttp.get.mockImplementation(myImplementation);

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 http.get() actually has multiple signatures. None of them will work – you have to combine them together into one.

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 @types/node/http.d.ts and combine them all together.

// From node_modules/@types/node/http.d.ts
function get(options: RequestOptions | string | URL, callback?: (res: IncomingMessage) => void): ClientRequest;
function get(url: string | URL, options: RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest;

// The implementation must accept either of these signatures, therefore:
// The first parameter is either "options" or "url", so it is either string, URL, or RequestOptions.
// The second parameter is either "callback" or "options", so it is optional and accepts either a callback or RequestOptions
// Only first overload has a third parameter, which is "callback", so it is optional and accepts a callback.
// Putting these together gives:
function (
    url: string | URL | RequestOptions,
    options?: RequestOptions | ((res: IncomingMessage) => void),
    callback?: (res: IncomingMessage) => void
): ClientRequest;

Now you can create your implementation with that function signature and pass it through to MockHttp.get.mockImplementation().

import * as http from 'node:http';

// Replace the http module with a mock implementation.
jest.mock('node:http');

// Create an alias with the correct type, so that TypeScript knows we are working with a mock.
const MockHttp = http as jest.Mocked<typeof http>;

const myImplementation = function (url: string | URL | http.RequestOptions, options?: http.RequestOptions | ((res: http.IncomingMessage) => void), callback?: (res: http.IncomingMessage) => void)
{
    // ...
}

// Success!
MockHttp.get.mockImplementation(myImplementation);

There are a few things to note when doing this:

  • Combine types using |.
  • Make the parameter optional with ? if it is optional in any overload.
  • Function signatures require an extra set of parentheses around them when used in combination with the | operator.

How to Draw Concentric Triangles in a Shader

25th September, 2025

A simple way to draw a triangle, or concentric triangles, in a shader.

Read more: How to Draw Concentric Triangles in a Shader

Given any point (u, v) in space, we wish to find the size of the triangle upon which that point lies. We can then use that size to draw the triangle.

We will define the size of the triangle as the distance between centre and the midpoint of each edge. The triangle is symmetrical about the y axis, with the horizontal edge on the bottom. The centre is at the origin, (0, 0).

  1. Calculate a as
    a = -v.
  2. Calculate b by rotating the edge to be vertical, then taking the horizontal part of the coordinate:
    b = rotate2d((abs(u), v), 90 - α).x
    where α is the angle between the base of the triangle and one side of the triangle.
  3. The size of the triangle is then the greater of a and b:
    size = max(a, b)

The size can then be used to daw the triangle:

  • To draw a filled triangle, colour any points where the size is less than a threshold.
  • To draw a triangular cutout, colour any points where the size is greater than a threshold.
  • To draw concentric triangles, colour any points where sin(size * frequency) > 0.

To make a non-symmetrical triangle perform step 2 twice, once with the angle of the left side and once with the angle of the right side.

To rotate, scale or translate the triangle: rotate, scale or translate (u, v) by the inverse of the effect required before performing this procedure.

Writing Generator Functions in C++

19th November, 2023
C++

Many languages have the ability to let you create generators: a function that can be called multiple times, picking up where it left off and returning a different value each time. Unfortunately C++ does not give you this functionality, however that doesn’t mean that we can’t implement it ourselves.

Read More >

How to Perform an Unbuffered Query in Laravel

26th September, 2023

If you wish to process a very large number of rows from a database then it may be prohibitively expensive to load them all into memory first. Laravel’s chunk() function may look like the solution however this performs a query for each chunk and is therefore extremely slow.

The ideal solution is to disable query buffering and thereby only ever have a single row in memory at once. Note that this option is specific to the MySQL PDO driver.

Read More >

How to Mock a Library with NodeJS, TypeScript, and Jest

18th September, 2023

The ability to provide a mock implementation of functionality is essential to unit testing, however the method for doing so with Jest and TypeScript is not well documented. This tutorial aims to elucidate the method for mocking a JavaScript library that is loaded into your TypeScript project. This is demonstrated with the ws WebSocket library but applies equally to any library, including built-in NodeJS modules.

Read More >

OpenTelemetry Null Span Exporter

24th August, 2023

The OpenTelemetry C++ implementation ships with several exporters for outputting your recorded traces: ostream, HTTP, gRPC, and more. It does not, however, provide a null implementation.

A null exporter is useful in test environments, where you just want to discard instrumentation data. The simple class below provides an implementation of a null span exporter.

Read More >

Impersonation in Laravel 10 with Sanctum

16th August, 2023

Impersonation is a useful tool: it allows an administrator to view the website as if they were logged in as another user, but without having to know their password. The Laravel documentation implies that you can do this using Auth::loginUsingId(), but you will find that this doesn’t work.

Read More >