Skip to main content

Function overloading with a variable number of arguments.

ce@neckar.it

Let’s assume we need to write a function in TypeScript that adds samples to some kind of store.

Additionally, we want to be able to pass a single sample, several samples or an array of samples to that function.

That is, we want to be able to write the following code:

// sample1, ..., sample5 are of type Sample
addSamples(sample1);
addSamples([sample4, sample5]);
addSamples(sample2, sample3);

How would we do that? A function that takes a single sample can be easily written:

function addSamples(sample: Sample): void {
    const store = [];
    store.push(sample);
    // do something with store
}
addSamples(sample1); // works
addSamples([sample4, sample5]); // error
addSamples(sample2, sample3); // error

So far so good. A function that takes an array of samples would look like this:

function addSamples(samples: Array<Sample>): void {
    const store = [];
    store.push(...samples);
    // do something with store
}
addSamples(sample1); // error
addSamples([sample4, sample5]); // works
addSamples(sample2, sample3); // error

Still not difficult. How would a function look like that accepts an arbitrary number of samples?
This is where „varargs“ come in handy:

function addSamples(...samples: Array<Sample>): void {
    const store = [];
    store.push(...samples);
    // do something with store
}
addSamples(sample1); // works
addSamples([sample4, sample5]); // error
addSamples(sample2, sample3); // works

Alright, but the goal is to have a single function that does everything at once.

How would such a function be implemented?

For this we need function overloading:

function addSamples(sample: Sample): void;
function addSamples(...samples: Array<Sample>): void;
function addSamples(sample: Array<Sample> | Sample, ...samples: Array<Sample>): void {
    const store = [];
    if (Array.isArray(sample)) {
        store.push(...sample); 
    } else {
        store.push(sample);
    }
    store.push(...samples)
    // do something with store
}

addSamples(sample1); // works
addSamples([sample4, sample5]); // works
addSamples(sample2, sample3); // works

With function overloading the signature of the implementing function must be the union of all signatures.

One can certainly argue if this solution is something to strive for.
Perhaps a more straight forward approach would be to have several functions with different names.
But in the end this was a requirement from a real-world project.

Feel free to adopt it to your needs.