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.
function greet(name?: string): string {
if (name === undefined) {
return "Привет, гость!";
}
return "Привет, " + name.toUpperCase() + "!";
}
console.log(greet()); // Привет, гость!
console.log(greet("Аня")); // Привет, АНЯ!Let's see what changed:
name?: stringmakes the parameter optional, so both calls,greet()andgreet("Аня"), pass the check.- Inside the function
namehas the typestring | undefined: when no argument is passed, it holdsundefined. An optional propertyage?: numberread the same way in the fifth theme. - The check
name === undefinednarrows the type, and after itnameis astring, which hastoUpperCase.
Remove the check, and tsc stops the method call:
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:
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.
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)); // 6A 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 isstring | undefined, and you need a check before using it;name = "гость"— inside the function the type isstring, 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:
function greet(name?: string = "гость"): string { // ✗
return "Привет, " + name + "!";
}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?: stringis an optional parameter; inside the function its type isstring | undefined, and it is checked before use.name = "гость"is a default value; inside the function the type isstring, and the value is used when the argument isundefined....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.