DEV Community

Cover image for How to implement Typescript Function overload
Gleb Krishin
Gleb Krishin

Posted on

How to implement Typescript Function overload

👋 Hey folks! In this post, I want to cover the topic of function overloading and explain why it's essential to understand this concept, and why you shouldn't be afraid to use it!

📃 Wiki Definition

Function overloading or method overloading is the ability to create multiple functions of the same name with different implementations. Calls to an overloaded function will run a specific version of that function appropriate to the context of the call.

🧐 Wiki Definition Explanation

In short function overloading is a function with multiple call signatures. This means there are multiple ways to call a function.

Example:
Let's take a look at the example of a function which might be called in a few ways with different arguments

type ProductParams = {
    promo?: boolean
    isArchived?: boolean;
};

function getProducts(params: ProductParams) {
    const url = new URL('/api/v1/products');
    const urlParams = new URLSearchParams();

    if ('promo' in params) {
        urlParams.append('promo', params.promo.toString());
    }

    if ('isArchived' in params) {
        urlParams.append('isArchived', params.isArchived.toString());
    }

    url.search = urlParams.toString();

    return fetch(url.toString()).then(res => res.json());
}
Enter fullscreen mode Exit fullscreen mode

You can call this function in 2 different ways, with 2 different params. Our function will return from the API products that might be promo or archived, or both promo and archived.

🔍 Multiple Function Signatures

Typescript's approach to function overloading is quite distinct from some other languages. Instead of having multiple function definitions, TypeScript uses multiple function signatures followed by a single function body.

The type-checker evaluates these signatures from top to bottom. This order matters because TypeScript will use the first signature that matches the function call. For instance, if a function call can match two overloaded signatures, TypeScript will choose the one that's listed first. Therefore, it's advisable to list more specific signatures higher and keep broader ones below.

💻 Let's implement the overloading for the example function

// Product Interfaces
interface PromoProducts {
    //... some properties specific to promo products
}

interface ArchivedProducts {
    //... some properties specific to archived products
}

interface PromoAndArchivedProducts {
    //... some properties combining both promo and archived products
}

type ProductParams = {
    promo?: boolean
    isArchived?: boolean;
};

// Function overloading signatures
function getProducts(params: { promo: true }): Promise<PromoProducts>;
function getProducts(params: { isArchived: true }): Promise<ArchivedProducts>;
function getProducts(params: { promo: true, isArchived: true }): Promise<PromoAndArchivedProducts>;

function getProducts(params: ProductParams) {
    const url = new URL('/api/v1/products');
    const urlParams = new URLSearchParams();

    if ('promo' in params) {
        urlParams.append('promo', params.maxPrice.toString());
    }

    if ('isArchived' in params) {
        urlParams.append('isArchived', params.isArchived.toString());
    }

    url.search = urlParams.toString();

    return fetch(url.toString()).then(res => res.json());
}
Enter fullscreen mode Exit fullscreen mode

After the implementation, we will be able to use our function in different ways and have a type of safety in place.

🏁 Finish

I recommend not being afraid to use function overloading. It's so helpful when you're providing type-rich interfaces and aiming for better code readability and safety.

Top comments (0)