2.12 Functions with rest parameters and the spread operator

Rest parameter can be used to implement functions that take an unknown number of parameters of the same type.

Getting Ready

All you need to be able to use rest parameters and the spread operator is an installation of TypeScript 1.5 or higher.

How to do it…

We can declare a rest parameter by preceding the parameter’s name with the spread operator (…) as follows:

function sume(...numbers: number[]) {
	let result = 0;
	for(var i = 0; i < numbers.length; i++) {
		result = result + numbers[i];
	}
	return result;
}

How it works…

The function above can take an unknown number of parameters. The number or argument can go from just one to infinite:

sume(2);         // OK
sume(2, 2);      // OK
sume(2, 2, 2);     // OK
sume(2, 2, 2, 2);   // OK
sume(2, 2, 2, 2, 2); // OK

We can check out the generated JavaScript output to understand how it works:

function sume() {
    <b>var numbers = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        numbers[_i - 0] = arguments[_i];
    }</b>
    var result = 0;
    for (var i = 0; i < numbers.length; i++) {
        result = result + numbers[i];
    }
    return result;
}

As we can see the TypeScript compiler is iterating the arguments object to create an array which contains all the arguments passed to the function at runtime.

The arguments object is an Array-like object corresponding to the arguments passed to a function.

There’s more…

The spread operator can be used not only when declaring rest parameters but when invoking a function which accepts rest parameters. The effect of doing so is the opposite of the previously explained, which means that an array is transformed into a list of parameters (as opposed to a list of parameters being transformed into an array):

function invokeSume(...numbers) {
	const sumeResult = sume(...numbers);
	return sumeResult;
}

When compiled it is transformed into:

function invokeSume() {
    var numbers = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        numbers[_i - 0] = arguments[_i];
    }
    var sumeResult = <b>sume.apply(void 0, numbers);</b>
    return sumeResult;
}

The key here is to notice the usage of the function’s apply method. The Mozilla developer network describes it as:

The apply() method calls a function with a given this value and arguments provided as an array (or an array-like object).

As opposed to optional parameters, rest parameters don’t need to be located in a particular position in the list of parameters of a function. For example:

function drawText(x: number, y: number, ...strings: string[]) {
    // draw text
}

drawText(10, 20, 'hello');
drawText(10, 20, 'hello', 'world');
var a = ['one', 'two'];
drawText(10, 20, ...a);
drawText(10, 20, 'zero', ...a, 'three');

Is transformed into:

function drawText(x, y) {
    var strings = [];
    for (var _i = 2; _i < arguments.length; _i++) {
        strings[_i - 2] = arguments[_i];
    }
    // draw text
}
drawText(10, 20, 'hello');
drawText(10, 20, 'hello', 'world');
var a = ['one', 'two'];
drawText.apply(void 0, <b>[10, 20].concat(a));</b>
drawText.apply(void 0, <b>[10, 20, 'zero'].concat(a, ['three']));</b>

Source Code

Functions with rest parameters and the spread operator


Shiv Kushwaha

Author/Programmer