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)