Add ? after a parameter name to make it optional. Callers may leave it out, and inside the function its type includes undefined.
TypeScript checks the argument count, so without the ? the first call would be a compile error: Expected 2 arguments, but got 1. (TS2554).
Optional Parameters Are Possibly undefined
Because a caller can omit it, an optional parameter's type inside the function is T | undefined. Under strictNullChecks you must handle the undefined case before using it as a T.
Optional chaining (?.) and nullish coalescing (??) are the usual tools here. When the fallback is a fixed value, a default parameter is shorter.
Default Parameter Values
A default value makes the parameter optional for callers and gives it a type without undefined inside the function. The type is inferred from the default, so the annotation is often unnecessary.
The caller sees the signature repeat(text: string, times?: number, separator?: string). Defaults follow JavaScript's rule: they apply when the argument is undefined, whether omitted or passed explicitly, and not when it is null. A default expression can use earlier parameters: function range(start: number, end = start + 10).
Parameter Order Rules
| Declaration | Compiles? | Notes |
|---|---|---|
(a: number, b?: number) | Yes | Optional parameters go last |
(a?: number, b: number) | No | TS1016: A required parameter cannot follow an optional parameter. |
(a = 0, b: number) | Yes | But callers must write f(undefined, 5) to use the default |
(a: number, ...rest: number[]) | Yes | A rest parameter is always last |
(a?: number, ...rest: number[]) | Yes | Optional before rest is allowed |
A defaulted parameter before a required one is legal but awkward. Its type for callers becomes number | undefined, and nobody enjoys writing undefined as a placeholder. If you need a flexible leading parameter, use an options object or function overloading instead.
Omitted vs undefined
x?: number and x: number | undefined look alike and have the same type inside the function. They differ for the caller: the first may be omitted, the second must be passed.
Use | undefined for a required argument that is allowed to have no value, so every caller has to think about it. Use ? when leaving it out is a normal call. (The message really says "1 arguments": that is TypeScript's wording.)
Rest Parameters
A rest parameter, ...name: T[], collects any number of arguments into an array. It must be the last parameter.
Spreading an array into fixed parameters is stricter. A rest parameter accepts a spread of any number[], but a function declared (a: number, b: number) only accepts a spread of a tuple, because TypeScript must know the length:
function point(x: number, y: number) { return { x, y }; }
const list = [3, 4]; // number[]
point(...list);
// error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
const pair = [3, 4] as const; // readonly [3, 4]
point(...pair); // fine
A rest parameter can also have a tuple type, which types each position: ...args: [name: string, age?: number].
Options Objects
Once a function has more than two or three optional parameters, callers lose track of positions. An options object with defaults gives named, order-free arguments.
The = {} at the end makes the whole object optional. Without it, fetchData("/a") is a compile error (Expected 2 arguments, but got 1., TS2554), and in plain JavaScript the same call would throw a TypeError at run time, because destructuring needs an object to read from.
Optional Parameters in Callback Types
In a function type, ? means "the caller of this callback may not pass it". It does not mean "the callback may skip it": a callback can always ignore trailing parameters. So do not mark callback parameters optional just to let handlers take fewer arguments.
// Too loose: every handler must now cope with index being undefined
type Visit = (item: string, index?: number) => void;
// Right: the caller always passes both; handlers may use only item
type VisitStrict = (item: string, index: number) => void;
const log: VisitStrict = (item) => console.log(item);
Frequently Asked Questions
How do you make a parameter optional in TypeScript?
Put a ? after its name: function greet(name?: string). Callers may leave it out, and inside the function its type is string | undefined, so you check it before using it. Giving the parameter a default value, name = "there", also makes it optional and removes the undefined inside the function.
Can an optional parameter come before a required one in TypeScript?
Not with ?: (a?: number, b: number) is error TS1016, "A required parameter cannot follow an optional parameter." A parameter with a default value may come first, but then callers must pass undefined explicitly to use the default, so in practice optional and defaulted parameters go last.
What is the difference between x?: number and x: number | undefined?
Inside the function both are number | undefined. The difference is at the call site: with x?: number the argument can be omitted, while with x: number | undefined it must be passed, even if the value is undefined. Leaving it out gives error TS2554.
Does passing null use the default parameter value?
No. JavaScript applies a default only when the argument is undefined (omitted or passed explicitly). null is a value, so it is kept. TypeScript rejects null for a number parameter under strictNullChecks anyway.
How do I pass an array as separate arguments in TypeScript?
Spread it: fn(...args). For a function with fixed parameters, the array must have a tuple type such as [number, number] or come from as const; spreading a number[] gives error TS2556 because its length is unknown. Spreading into a rest parameter (...values: number[]) always works.