Learning TypeScript 2.x
上QQ阅读APP看书,第一时间看更新

Functions with REST parameters

We have learned how to use optional and default parameters to increase the number of ways that we can invoke a function. Let's return one more time to the previous example:

function add(foo: number, bar: number, foobar: number = 0): number { 
    return foo + bar + foobar; 
} 

We have learned how to invoke the add function with two or three parameters, but what if we wanted to allow other developers to pass four or five parameters to our function? We would have to add two extra default or optional parameters. And what if we wanted to allow them to pass as many parameters as they need? The solution to this possible scenario is the use of REST parameters. The REST parameter syntax allows us to represent an indefinite number of arguments as an array:

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

As we can see in the preceding code snippet, we have replaced the function parameters foo, bar, and foobar with just one parameter named foo. Note that the name of the parameter foo is preceded by an ellipsis (a set of three periods—not the actual ellipsis character). A REST parameter must be of an array type or we will get a compilation error. We can now invoke the add function with as many parameters as we need:

add(); // 0 
add(2); // 2 
add(2, 2); // 4 
add(2, 2, 2); // 6 
add(2, 2, 2, 2); // 8 
add(2, 2, 2, 2, 2); // 10 
add(2, 2, 2, 2, 2, 2); // 12 

Although there is no specific limit to the theoretical maximum number of arguments that a function can take, there are, of course, practical limits. These limits are entirely implementation-dependent and, most likely, will also depend on exactly how we are calling the function.

JavaScript functions have a built-in object called the arguments object. This object is available as a local variable named arguments. The arguments variable contains an object like an array that contains the arguments used when the function was invoked.

The arguments object exposes some of the methods and properties provided by a standard array, but not all of them. Refer to the documentation at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments to learn more about its peculiarities.

If we examine the JavaScript output, we will notice that TypeScript iterates the arguments object to add the values to the foo variable:

function add() { 
    var foo = []; 
    for (var _i = 0; _i < arguments.length; _i++) { 
        foo[_i - 0] = arguments[_i]; 
    } 
    var result = 0; 
    for (var i = 0; i < foo.length; i++) { 
        result += foo[i]; 
    } 
    return result; 
} 

We can argue that this is an extra, unnecessary iteration over the function's parameters. Even though it is hard to imagine this extra iteration becoming a performance issue, if you think that this could be a problem for the performance of your application, you may want to consider avoiding the use of REST parameters and use an array as the only parameter of the function instead:

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

The preceding function takes an array of numbers as its only parameter. The invocation API will be a little bit different from the REST parameters, but we will effectively avoid the extra iteration over the function's argument list:

add(); // Error, expected 1 arguments, but got 0. 
add(2); // Error, '2' is not assignable to parameter of type 'number[]'. 
add(2, 2); // Error, expected 1 arguments, but got 2. 
add(2, 2, 2); // Error, expected 1 arguments, but got 3. 
 
add([]); // returns 0 
add([2]); // returns 2 
add([2, 2]); // returns 4 
add([2, 2, 2]); // returns 6