Default parameters in TypeScript let you define fallback values for function arguments so your code behaves predictably even when some callers omit certain arguments. In real-world applications, such as API wrappers, UI handlers, and business logic services, good defaults make your functions easier to use, safer to refactor, and more self-documenting.
What Are Default Parameters in TypeScript?
Default parameters allow you to assign a default value to a function parameter. If the function is called without a value for that parameter, or with undefined, the default value is used.
This is especially useful when:
- You want to make a parameter optional for most callers
- You want your function to always have a usable value at runtime
- You want to avoid repetitive if (!param) { … } checks inside the function body
Example idea:
- A logging function that defaults to “info” level
- A discount function with a default discount rate
- A greeting function that defaults to “Guest”
Syntax of Default Parameters
The syntax for default parameters is straightforward: assign a value in the function declaration.
function functionName(parameter: type = defaultValue) {
// function body
}You can define multiple parameters, with some or all of them having defaults:
function createUser(
name: string,
isActive: boolean = true,
role: "user" | "admin" = "user"
) {
return { name, isActive, role };
}
const user1 = createUser("Alice"); // isActive = true, role = "user"
const user2 = createUser("Bob", false, "admin");
Default parameters also work with arrow functions, which is very common in modern TypeScript projects:
const logEvent = (event: string, level: "info" | "error" = "info") => {
console.log(`[${level}] ${event}`);
};
logEvent("App started"); // [info] App started
logEvent("App failed", "error"); // [error] App failedImportant rule: Default parameters typically come after required parameters. This makes calling the function simpler and avoids confusing parameter ordering.
Default Parameters vs Optional Parameters
TypeScript also supports optional parameters using ?, for example parameter?: type. It’s important to understand how this differs from default parameters.
Optional parameters
function sendEmail(
to: string,
subject: string,
body?: string
) {
// body can be string or undefined
}
bodymay beundefined- There is no default value; callers decide whether to provide this argument
- You often need to handle the
undefinedcase inside the function
Default parameters
function sendEmailWithDefaultBody(
to: string,
subject: string,
body: string = "No message provided"
) {
// body is always a string at runtime
}
bodyalways has a value at runtime- When the caller omits the argument or passes
undefined, the default is applied - Callers don’t need to think about a “no message” case if the default is acceptable
When to use what:
- Use optional parameters when the absence of a value (undefined) has meaning in your logic
- Use default parameters when you always want a usable runtime value, and a sensible default exists
Example 1: Greeting Function with a Default Name
Let’s start with a simple greeting function that uses a default name when no value is provided.
function greet(name: string = "Guest") {
console.log(`Hello, ${name}! Welcome to our application.`);
}
// Calling the function without an argument
greet();
// Output: Hello, Guest! Welcome to our application.
// Calling the function with an argument
greet("John");
// Output: Hello, John! Welcome to our application.I executed the above example code and added the screenshot below.

This pattern is cleaner than writing:
function greetLegacy(name?: string) {
const finalName = name ?? "Guest";
console.log(`Hello, ${finalName}!`);
}Using a default parameter moves the defaulting logic into the function signature, making the API more self-documenting.
Example 2: Calculate Discounts with Default Rate
Here’s a more practical example from e-commerce or billing scenarios. Suppose you want to calculate the final price after applying a discount, but when no discount rate is passed, you want to default to 10%.
function calculateDiscount(
price: number,
discountRate: number = 0.1
): number {
return price - price * discountRate;
}
// Calling the function without a discount rate
console.log(calculateDiscount(100));
// Output: 90
// Calling the function with a discount rate
console.log(calculateDiscount(100, 0.2));
// Output: 80
I executed the above example code and added the screenshot below.

In real-world projects, you often prefer an options object instead of long parameter lists. You can combine options with defaults like this:
interface DiscountOptions {
rate?: number;
}
function calculateDiscountWithOptions(
price: number,
options: DiscountOptions = {}
): number {
const rate = options.rate ?? 0.1;
return price - price * rate;
}
console.log(calculateDiscountWithOptions(100)); // 90
console.log(calculateDiscountWithOptions(100, { rate: 0.2 })); // 80This pattern scales better as you add more configuration (e.g., discount type, currency, rounding strategy).
Example 3: Fetch User Data with a Default User ID
In many applications, you need to fetch user data, sometimes falling
user (like a demo user or a system account).
interface User {
id: string;
name: string;
}
async function fetchUserData(
userId: string = "defaultUser"
): Promise<User> {
console.log(`Fetching data for user: ${userId}`);
// Simulated fetch logic
// In real code, you might call fetch/axios here
return {
id: userId,
name: userId === "defaultUser" ? "Default User" : "Sample User"
};
}
// Calling the function without a user ID
fetchUserData().then(user => console.log(user));
// Fetching data for user: defaultUser
// Calling the function with a user ID
fetchUserData("user123").then(user => console.log(user));
// Fetching data for user: user123I executed the above example code and added the screenshot below.

In a production system, consider whether a hard-coded default user is appropriate. For sensitive operations, it might be better to require callers to explicitly provide a user ID or to inject a default via configuration.
How Default Parameters Handle undefined and null
A subtle but important detail is how default parameters behave with undefined and null.
- Default parameters are applied when the argument is undefined or omitted
- Default parameters are not applied when the argument is null or any other value
Consider this example:
function logValue(value: string = "default") {
console.log(value);
}
logValue(); // "default"
logValue(undefined as any); // "default"
logValue("Hello"); // "Hello"
logValue(null as any); // "null"Key points:
- Calling logValue() or logValue(undefined) will use the default “default”
- Passing null is treated as a normal value at runtime, so the default is not applied
- With strictNullChecks enabled, you typically model
nullandundefinedexplicitly in the type if you need both
Design your APIs so that callers understand whether they should pass undefined, null, or nothing at all. Mixing all three without a clear convention can quickly become confusing.
Real-World Pattern: Default Parameters in UI Handlers
In frontend applications (React, Angular, Vue), default parameters are often used in event handlers and helper functions.
type Theme = "light" | "dark";
function applyTheme(theme: Theme = "light") {
// Apply the selected theme
console.log(`Applying theme: ${theme}`);
}
// In a click handler, you might call:
applyTheme(); // light theme
applyTheme("dark"); // dark theme
This is helpful when you have multiple controls or routes that rely on the same function but do not always specify a theme explicitly.
Another example is a pagination helper:
interface FetchPageOptions {
page?: number;
pageSize?: number;
}
function fetchPage(
resource: string,
{ page = 1, pageSize = 20 }: FetchPageOptions = {}
) {
console.log(`Fetching ${resource}, page ${page}, size ${pageSize}`);
}
fetchPage("orders"); // page 1, size 20
fetchPage("orders", { page: 2 }); // page 2, size 20
fetchPage("orders", { pageSize: 50 }); // page 1, size 50Here, defaults are applied via destructuring, giving you clean, expressive function signatures.
When You Should Avoid Default Parameters
Default parameters are powerful, but they are not always the right choice. Overusing them can hide bugs or create confusing APIs.
Avoid default parameters when:
- The default value is expensive to compute
- In such cases, compute the value lazily inside the function only when needed
- The default depends on dynamic context (for example, current user, request context, tenant)
- Use dependency injection or pass a context object instead
- Defaulting an object might hide missing data
- Automatically defaulting to {} can hide bugs where callers forget to pass the required configuration
Example anti-pattern:
// Anti-pattern: silently defaulting to an empty config
interface Config {
featureFlag: boolean;
}
function initializeFeature(config: Config = { featureFlag: false }) {
// If caller forgets to pass config, you might silently disable a feature
console.log(config.featureFlag);
}
A better design might force callers to pass the configuration or use a clearly named factory:
function createDefaultConfig(): Config {
return { featureFlag: false };
}
function initializeFeature(config: Config) {
console.log(config.featureFlag);
}
initializeFeature(createDefaultConfig());This makes the defaulting logic explicit and easier to reason about when debugging.\
Hands-On Exercises
If you want to reinforce your understanding, try these small exercises:
- Logging with default level
- Write a logMessage function that takes message: string and level: “info” | “warn” | “error”, with “info” as the default level.
- Call it with and without the level parameter.
- Report generator
- Create a generateReport function that takes title: string, includeDate: boolean (default
true), and format: “pdf” | “html” (default “pdf”). - Print different messages based on the arguments.
- Create a generateReport function that takes title: string, includeDate: boolean (default
- Options object with defaults
- Define an EmailOptions interface with
from?,cc?,bcc?. - Create a sendEmailWithOptions(to: string, subject: string, options?: EmailOptions) function that applies sensible defaults using destructuring and default values.
- Define an EmailOptions interface with
Try implementing each exercise with both optional and default parameters to see which style feels clearer in each case.
Conclusion
Default parameter values in TypeScript are a simple feature that can dramatically improve the usability and readability of your functions. By choosing sensible defaults, you reduce boilerplate, make your APIs easier to call, and keep business logic focused on what really matters instead of argument validation.
Use default parameters when a clear, safe fallback exists, and reserve optional parameters or explicit configuration objects for cases where the absence of a value carries meaning. With the patterns in this guide, you can design TypeScript functions that are both developer-friendly and robust in production.
You may also like to read:
- TypeScript Record vs Object
- Conditionally Add Property to Object in TypeScript
- How to Extend Interfaces with Classes in TypeScript?
- Check if an Object Has a Property in TypeScript

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.