Grokking TypeScript
Vote

0% completed

​

Optional and Default Parameters

Optional Parameters

Default Parameters

Default Parameters Before Required Ones

Combining Optional and Default Parameters

Choosing Between Them

What should happen when a caller leaves out an argument? JavaScript sets the parameter to undefined and runs the function anyway, while TypeScript treats every declared parameter as required and reports the call.

function formatPrice(amount: number, currency: string): string { return `${amount} ${currency}`; } console.log(formatPrice(100)); // Error
error TS2554: Expected 2 arguments, but got 1.

If you run the emitted JavaScript anyway, it prints 100 undefined, which is the mistake the compiler was reporting. Many functions do have a sensible behavior when an argument is missing, so TypeScript lets you declare that in two ways: an optional parameter or a default parameter.

Optional Parameters

A question mark after the parameter name makes the parameter optional, which means the caller may leave it out. When the caller does, the value of the parameter is undefined. This changes two things that the compiler checks, one for the caller and one for the body.

For the caller, the argument is no longer required. For the body, the type of the parameter becomes string | undefined, because the value may be missing. The compiler therefore rejects any use that would fail on undefined.

function formatPrice(amount: number, currency?: string): string { return `${amount} ${currency.toUpperCase()}`; // Error }
error TS18048: 'currency' is possibly 'undefined'.

Before a use like that one, you must handle the missing case. One way is an if check, and after that check the compiler knows that currency is a string.

function formatPrice(amount: number, currency?: string): string { if (currency) { return `${amount} ${currency.toUpperCase()}`; } return `${amount} USD`; } console.log(formatPrice(100)); // Output: 100 USD console.log(formatPrice(100, "eur")); // Output: 100 EUR console.log(formatPrice(100, "")); // Output: 100 USD

Look at the last call. The if (currency) check treats an empty string as missing, because an empty string counts as false in a condition. The same happens with 0 for a number parameter, and 0 is often a real value.

When only a truly missing value should count as missing, use the nullish coalescing operator ??. It gives the right side only when the left side is null or undefined.

function formatPrice(amount: number, currency?: string): string { return `${amount} ${currency ?? "USD"}`; } console.log(formatPrice(100)); // Output: 100 USD console.log(formatPrice(100, "EUR")); // Output: 100 EUR console.log(formatPrice(100, "")); // Output: 100 (with an empty currency after it)

The last call now keeps the empty string, because ?? replaces only a missing value. Choose the check that matches what the empty value means in your function.

An optional parameter must come after every required parameter. Without this rule, the compiler could not tell which parameter a shorter argument list was meant to fill.

function formatPrice(currency?: string, amount: number): string { // Error return `${amount} ${currency ?? "USD"}`; }
error TS1016: A required parameter cannot follow an optional parameter.

Default Parameters

The last example supplied "USD" inside the body. A default parameter moves that value into the parameter list, so the signature documents it and the body no longer handles a missing value.

function formatPrice(amount: number, currency: string = "USD"): string { return `${amount} ${currency}`; } console.log(formatPrice(100)); // Output: 100 USD console.log(formatPrice(100, undefined)); // Output: 100 USD console.log(formatPrice(100, "EUR")); // Output: 100 EUR

Inside the body, currency is always a string, because the default has already replaced a missing value. Outside the function, callers see currency?: string, so they may leave it out. You could also write currency = "USD" with no annotation, because the compiler infers the type string from the default value.

The default is used in only one situation: when the argument is undefined, either because it was left out or because the caller passed undefined. The picture below follows each kind of argument for this function.

Leaving the argument out or passing undefined gives the default, a string is used as given, and null is a compile error.
Leaving the argument out or passing undefined gives the default, a string is used as given, and null is a compile error.

The case of null deserves attention. It does not trigger the default, and the compiler rejects it under strict mode.

function formatPrice(amount: number, currency: string = "USD"): string { return `${amount} ${currency}`; } formatPrice(100, null); // Error
error TS2345: Argument of type 'null' is not assignable to parameter of type 'string | undefined'.

If you run the emitted JavaScript anyway, this call returns 100 null, because a default never replaces null at runtime.

A parameter cannot be optional and have a default at the same time, because the default already makes it optional.

function formatPrice(amount: number, currency?: string = "USD"): string { // Error return `${amount} ${currency}`; }
error TS1015: Parameter cannot have question mark and initializer.

A default value can also use an earlier parameter, because the default is evaluated at each call.

function totalWithTax(price: number, tax: number = price / 2): number { return price + tax; } console.log(totalWithTax(100)); // Output: 150 console.log(totalWithTax(100, 0)); // Output: 100

Default Parameters Before Required Ones

Unlike an optional parameter, a default parameter may come before a required one. The caller then has to pass undefined explicitly to get the default, because the argument positions must still line up.

function formatPrice(currency: string = "USD", amount: number): string { return `${amount} ${currency}`; } console.log(formatPrice(undefined, 100)); // Output: 100 USD console.log(formatPrice("EUR", 100)); // Output: 100 EUR formatPrice(100); // Error
error TS2554: Expected 2 arguments, but got 1.

This is legal but awkward for the caller, so place default parameters last unless you have a specific reason not to.

Combining Optional and Default Parameters

One function can use both kinds. To skip a parameter in the middle and set one after it, pass undefined in the skipped position.

function describeOrder(item: string, note?: string, isPaid: boolean = true): string { const noteText = note ?? "none"; return `Item: ${item}, Note: ${noteText}, Paid: ${isPaid}`; } console.log(describeOrder("Laptop")); console.log(describeOrder("Phone", "Gift wrap")); console.log(describeOrder("Tablet", undefined, false));
Item: Laptop, Note: none, Paid: true Item: Phone, Note: Gift wrap, Paid: true Item: Tablet, Note: none, Paid: false

Choosing Between Them

Use a default parameter when one value is correct for most callers, because the body then has one case to handle. Use an optional parameter when a missing value has its own meaning, for example when an order simply has no note and the function must behave differently. An optional parameter costs a check in the body, and the compiler reports an error only when a use would fail on undefined. It does not report a template string such as ${amount} ${currency}, and that string produces 100 undefined when the argument is missing.

Reading Progress

0%


Vote for new content

On This Page

Optional Parameters

Default Parameters

Default Parameters Before Required Ones

Combining Optional and Default Parameters

Choosing Between Them