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.
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.
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:
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 occurredBecause 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:
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:
'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:
// 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:
// 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:
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:
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-7Passing 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:
// 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:
// 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:
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:
| Feature | Optional | Default |
|---|---|---|
| Type includes undefined | Yes | No |
| Runtime value when omitted | undefined | The default value |
| Can appear in any position | After required params only | After 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:
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:
optional();
withDefault();
// Output: undefined
// Output: GuestChoose 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:
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
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.
Frequently Asked Questions
What happens when I call a function without an optional parameter?
Can optional parameters appear before required parameters?
Should I use optional parameters or default parameters?
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.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.