Skip to content
Theory · Functions · lesson 3 of 10

Optional, default and rest parameters

tsc won't let area(3) through for a function with two parameters: there must be as many arguments as parameters. Yet JavaScript has plenty of functions whose argument you may leave out. greet() says hello to a guest, and greet("Аня") says hello to Anya. How do you say that in a signature?

Back to the tea machine. Besides the coin slot it has buttons, and the plate covers them too:

  • "Sugar — if you like": you may skip the button, and then there is no sugar;
  • "No size chosen — you get a medium": if nobody presses the button, the machine picks the usual option itself;
  • "Takes any number of coins": drop in as many as you like, the machine counts them all.

In TypeScript each of these lines of the plate has its own syntax.

Three kinds of parameters

An optional parameter

A ? after a parameter's name says: the argument may be left out.

TypeScript
function greet(name?: string): string {
    if (name === undefined) {
        return "Привет, гость!";
    }
    return "Привет, " + name.toUpperCase() + "!";
}

console.log(greet()); // Привет, гость!
console.log(greet("Аня")); // Привет, АНЯ!

Let's see what changed:

  1. name?: string makes the parameter optional, so both calls, greet() and greet("Аня"), pass the check.
  2. Inside the function name has the type string | undefined: when no argument is passed, it holds undefined. An optional property age?: number read the same way in the fifth theme.
  3. The check name === undefined narrows the type, and after it name is a string, which has toUpperCase.

Remove the check, and tsc stops the method call:

TEXT
error TS18048: 'name' is possibly 'undefined'.

The message means: "name may be undefined". Optional parameters come after required ones: for the signature (greeting?: string, name: string) tsc reports error TS1016 — a required parameter cannot follow an optional one.

A default value

If the function should take a usual value when no argument comes, you write it right in the parameter, as in JavaScript:

TypeScript
function greet(name = "гость"): string {
    return "Привет, " + name + "!";
}

console.log(greet()); // Привет, гость!
console.log(greet("Аня")); // Привет, Аня!
console.log(greet(undefined)); // Привет, гость!

TypeScript inferred the parameter's type from the default value: name is a string. Inside the function name is always a string, so there is nothing to check. For the calling code the parameter is optional: the hover over greet shows function greet(name?: string): string.

The default value is used when the argument is undefined. It makes no difference whether the argument was left out or undefined was passed explicitly, as in the third call.

A rest parameter

A parameter with three dots before its name is a rest parameter: it gathers all the remaining arguments into an array.

TypeScript
function sum(...nums: number[]): number {
    let total = 0;
    for (const n of nums) {
        total += n;
    }
    return total;
}

console.log(sum()); // 0
console.log(sum(1, 2, 3)); // 6

A rest parameter has an array type: nums: number[]. The number of arguments is now free, even zero, but each one must be a number. sum(1, "2") gives the familiar error TS2345: a string cannot be passed where a number is expected. A rest parameter can only be the last one.

? or a default value

Interviewers like to ask how an optional parameter differs from a parameter with a default value. Both let the caller leave the argument out, and the difference is the type inside the function:

  • name?: string — inside the function the type is string | undefined, and you need a check before using it;
  • name = "гость" — inside the function the type is string, and no check is needed.

This is where the machine analogy ends. On a real machine, "didn't press the button" and "pressed 'no sugar'" are different actions. In JavaScript a missing argument and an explicit undefined look the same: the default value kicks in for both.

Common mistake

A ? and a default value were put on one parameter, to stress that it is optional:

TypeScript
function greet(name?: string = "гость"): string { // ✗
    return "Привет, " + name + "!";
}
TEXT
error TS1015: Parameter cannot have question mark and initializer.

The message means: "a parameter cannot have both a question mark and an initial value". The default value already makes the parameter optional, so the ? is redundant here: name = "гость" is enough.

Key points

  • name?: string is an optional parameter; inside the function its type is string | undefined, and it is checked before use.
  • name = "гость" is a default value; inside the function the type is string, and the value is used when the argument is undefined.
  • ...nums: number[] gathers the remaining arguments into an array; each argument is checked against the element type.
  • Optional parameters and the rest parameter come last, and a ? and a default value are never combined on one parameter.