Optional Parameters in TypeScript

Mark a function parameter as optional with the ? syntax. Learn how optional parameters work, how they interact with undefined, and the key rule for callbacks.

5 min read

TypeScript optional parameters let a caller skip an argument the function does not strictly need. Mark the parameter with a question mark after its name. When the caller omits it, the parameter receives undefined at runtime, and TypeScript automatically adds undefined to its type.

typescripttypescript
function greet(name: string, title?: string) {
  if (title) {
    return `Hello, ${title} ${name}!`;
  }
  return `Hello, ${name}!`;
}
 
console.log(greet("Alice"));
console.log(greet("Bob", "Dr."));
// Output: Hello, Alice!
// Output: Hello, Dr. Bob!

The question mark after title means the argument can be provided or skipped, and both calls above are valid. Inside the function, the parameter can be a string or undefined, so the code checks for a value before using it.

How Optional Parameters Work

Marking a parameter with ? automatically adds undefined to its type, so writing prefix?: string behaves the same as writing the union type by hand. The question mark also lets callers omit the argument entirely:

typescripttypescript
function log(message: string, prefix?: string) {
  const fullMessage = prefix ? `[${prefix}] ${message}` : message;
  console.log(fullMessage);
}
 
log("User signed in");
log("Error occurred", "ERROR");
// Output: User signed in
// Output: [ERROR] Error occurred

Because the parameter type includes undefined, the function body must handle the missing case. With strictNullChecks enabled, TypeScript reports an error if the code uses the parameter without checking for a value first:

typescripttypescript
function badLog(message: string, prefix?: string) {
  console.log(prefix.toUpperCase());
}

Calling a string method directly on an optional parameter is unsafe, since the value might be undefined at runtime, so the compiler blocks it with this error:

texttext
'prefix' is possibly 'undefined'.

The check is what you would write in JavaScript anyway. TypeScript just makes sure you do not forget it. For the base rules on annotating parameters, see type function parameters in TypeScript.

Ordering Rules

All optional parameters must come after all required parameters. You cannot put an optional parameter before a required one:

typescripttypescript
// Error: A required parameter cannot follow an optional parameter
function greet(title?: string, name: string) {
  // ...
}

The reason is positional: arguments are matched to parameters by position. If the first parameter were optional, TypeScript could not tell whether greet("Alice") meant "Alice as title, no name" or "no title, Alice as name." The compiler rejects the declaration itself before the function is ever called, so this mistake is caught immediately while you write the code.

Always order parameters from required to optional:

typescripttypescript
// Correct: required parameter first, optional parameter second
function greet(name: string, title?: string) {
  // ...
}

Explicit undefined

Even when a parameter is optional, callers can explicitly pass undefined instead of leaving the argument out entirely, and the function treats both cases the same way:

typescripttypescript
function formatDate(year: number, month: number, day?: number) {
  if (day !== undefined) {
    return `${year}-${month}-${day}`;
  }
  return `${year}-${month}`;
}

Calling this function with two arguments, three arguments, or an explicit undefined third argument all produce a valid, well-typed result:

typescripttypescript
console.log(formatDate(2026, 7));
console.log(formatDate(2026, 7, 17));
console.log(formatDate(2026, 7, undefined));
// Output: 2026-7
// Output: 2026-7-17
// Output: 2026-7

Passing undefined explicitly behaves the same as omitting the argument. The function body sees undefined in both cases, which is why the first and third calls produce the same result. This matters when a value is forwarded from another function, such as a config object property that may or may not be set.

Optional Parameters in Callbacks: The Key Rule

There is one rule about optional parameters in callbacks that causes confusion. When you write a function type for a callback, never mark a callback parameter as optional unless you intend to call the callback without that argument.

Consider this incorrect pattern:

typescripttypescript
// Wrong: index is marked optional in the callback type
function myForEach(
  arr: string[],
  callback: (item: string, index?: number) => void
) {
  for (let i = 0; i < arr.length; i++) {
    callback(arr[i], i);
  }
}

Marking the second parameter as optional in the callback type claims the implementation might call the callback with only one argument. But the implementation always passes two arguments, so the question mark tells TypeScript a lie.

The correct type does not mark that parameter as optional:

typescripttypescript
// Correct: both parameters are required in the callback type
function myForEach(
  arr: string[],
  callback: (item: string, index: number) => void
) {
  for (let i = 0; i < arr.length; i++) {
    callback(arr[i], i);
  }
}

Callers can still omit parameters they do not need, even though the callback type declares both of them as required parameters in its signature:

typescripttypescript
myForEach(["a", "b", "c"], (item) => {
  console.log(item);
});
// Output: a, b, c (printed on separate lines)

The caller wrote a callback with only one parameter, and TypeScript accepts it. This is because of the parameter count compatibility rule: a function with fewer parameters is always compatible with a function type expecting more parameters.

The rule is: when writing a callback type, declare all the parameters you will actually pass. Let callers omit the ones they do not need.

Optional Parameters With Default Values

An optional parameter is different from a default parameter, even though both let callers omit the argument:

FeatureOptionalDefault
Type includes undefinedYesNo
Runtime value when omittedundefinedThe default value
Can appear in any positionAfter required params onlyAfter required params only
Use case"This might not be provided""Use this fallback when missing"

The next example shows the difference directly. Omitting the argument leaves the optional parameter as undefined, while the default parameter falls back to a concrete value:

typescripttypescript
function optional(title?: string) {
  console.log(typeof title);
}
 
function withDefault(title: string = "Guest") {
  console.log(title);
}

Calling each function with no argument at all shows the real difference in what the parameter actually holds once the function starts running:

typescripttypescript
optional();
withDefault();
// Output: undefined
// Output: Guest

Choose optional when a missing value means something in your logic, such as a filter that was not applied. Choose a default when you always need a concrete value. For more on defaults, see default parameters in TypeScript.

Common Mistakes

Marking callback parameters as optional. As explained above, a question mark on a callback parameter tells TypeScript the callback might not receive that argument. Only use it when the call site genuinely sometimes omits the argument.

Checking optional parameters with truthiness instead of undefined. An empty string and the number 0 are falsy but valid values. Prefer an explicit undefined check instead of a truthiness check when the type includes a falsy valid value:

typescripttypescript
function repeat(text: string, times?: number) {
  const count = times !== undefined ? times : 1;
  return text.repeat(count);
}
 
console.log(repeat("Hi", 0));
// Output: "" (an empty string, because repeat(0) returns "")

The explicit undefined check correctly handles 0, which a plain truthiness check would have replaced with 1.

Rune AI

Rune AI

Key Insights

  • Mark a parameter as optional with ? after the name: param?: Type.
  • An optional parameter's type becomes Type | undefined.
  • Optional parameters must come after all required parameters.
  • Never mark callback parameters as optional unless you skip them at the call site.
  • The ? syntax only exists at compile time and is erased from JavaScript.
RunePowered by Rune AI

Frequently Asked Questions

What happens when I call a function without an optional parameter?

The parameter receives the value undefined at runtime. TypeScript adds undefined to the parameter's type, so you must handle the missing case in the function body.

Can optional parameters appear before required parameters?

No. All optional parameters must come after all required parameters. TypeScript enforces this because callers provide arguments positionally, and a gap would be ambiguous.

Should I use optional parameters or default parameters?

Use optional parameters when undefined has a meaningful meaning, such as a search filter that may or may not be applied. Use default parameters when you want a concrete fallback value.

Conclusion

Optional parameters let callers omit arguments when the function can work without them. Mark a parameter with ? after its name, and TypeScript adds undefined to its type. Always place optional parameters after required ones. For callbacks, never mark a callback parameter as optional unless you intend to call the callback without that argument.