Lesson 3-2 used bio?: string to make an object property optional, and the same symbol appears on parameters in function greet(name: string, title?: string).
The meaning carries over exactly: ? marks something that may be absent. A caller can write greet("Ada") or greet("Ada", "Dr."), and inside the function you must handle the undefined case before using title as a string.
That symmetry is deliberate. Optionality is one idea in TypeScript, whether it applies to a property in a shape or to an argument in a call.
Parameters callers may skip
In JavaScript every parameter was silently optional, missing ones just became undefined. TypeScript flips that: parameters are required unless you say otherwise.
function greet(name: string, title?: string): string
title? allows the two-argument and one-argument calls, and inside the body title has type string | undefined, the union from Unit 4. Narrow it with a check before use.
A default parameter goes one step further and supplies the fallback value itself:
function ticketPrice(age: number, discount: number = 0): number
With a default, the parameter is optional for callers but never undefined inside the body, so no check is needed. Optional parameters must come after required ones.
Calling a function with and without its optional argument
function greet(name: string, title?: string): string { if (title !== undefined) { return "Hello, " + title + " " + name; } return "Hello, " + name; } console.log(greet("Ada")); console.log(greet("Ada", "Dr."));
Output
Hello, Ada Hello, Dr. Ada
Both calls compile because only the second parameter is optional. Calling greet() with no arguments at all is an error, since name is marked neither with ? nor with a default value, and only parameters that carry one of those may be omitted.
The if (title !== undefined) guard is required rather than stylistic. Inside the function title has type string | undefined, so the guard is what narrows it to a plain string before it is concatenated.
ticketPrice: a parameter with a default value
ticketPrice(age: number, discount: number = 0) charges 5 for children under 12 and 12 for everyone else, then subtracts any discount.
function ticketPrice(age: number, discount: number = 0): number { const base = age < 12 ? 5 : 12; return base - discount; } console.log(ticketPrice(30)); console.log(ticketPrice(8, 2));
Output
12 3
How the default changes things
- A default value is written straight into the signature as
discount: number = 0. There is no separate declaration and no check at the top of the body. - Because of the default,
ticketPrice(30)is a legal call anddiscountis0inside the function, notundefined. That is the key difference from an optional parameter: the type inside the body stays plainnumber, so no narrowing is needed. age < 12 ? 5 : 12is the conditional operator from lesson 3-2 choosing the base price, andticketPrice(8, 2)therefore computes5 - 2.
Rest parameters: any number of arguments
console.log happily takes one argument or five, and your own functions can too. A rest parameter collects every remaining argument into an array. Declare it with ... and give it an array type:
function sum(...nums: number[]): number
Callers write sum(1, 2, 3) or sum(). Inside the body, nums is an ordinary number[] you can loop over.
Two rules follow from what it is. A rest parameter must come last, because it absorbs everything after it, and its type must be an array type, because an array is what the collected arguments become.
The payoff is that variable-argument functions stay fully checked. sum(1, "2") is a compile error, not a NaN discovered at runtime.
sum: adding a variable number of arguments
sum(...nums: number[]) adds every argument it receives and returns the total, whether that is three arguments, two, or none at all.
function sum(...nums: number[]): number { let total = 0; for (const n of nums) { total += n; } return total; } console.log(sum(1, 2, 3)); console.log(sum(10, 20)); console.log(sum());
Output
6 30 0
Reading the rest parameter
- The three dots go in the declaration, as
function sum(...nums: number[]). Callers never write dots, they just pass arguments normally. - Inside the body
numsis an ordinarynumber[], so thefor...ofloop is the same one you have written since the JavaScript course. - With no arguments at all,
numsis an empty array, the loop body never runs, and the initialtotalof0comes back. That is the natural identity for addition, so the empty case needs no special handling. - Because the element type is
number, a call likesum(1, "2")is a compile error rather than aNaNdiscovered later at runtime.