Function overloading with a variable number of arguments.

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);Code-Sprache: TypeScript (typescript)

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); // errorCode-Sprache: TypeScript (typescript)

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); // errorCode-Sprache: TypeScript (typescript)

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); // worksCode-Sprache: TypeScript (typescript)

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); // worksCode-Sprache: TypeScript (typescript)

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.