Question
How can I set a default value for a property on an object parameter in TypeScript?
For example, given this function:
function sayName(params: { firstName: string; lastName?: string }) {
params.lastName = params.lastName || 'smith';
const name = params.firstName + params.lastName;
alert(name);
}
sayName({ firstName: 'bob' });
Is there a better alternative to assigning the default inside the function body with:
params.lastName = params.lastName || 'smith';
I was hoping something like this might work directly in the type annotation:
function sayName(params: { firstName: string; lastName: string = 'smith' }) {
I know that for normal function parameters, TypeScript supports defaults like this:
function sayName(firstName: string, lastName = 'smith') {
const name = firstName + lastName;
alert(name);
}
sayName('bob');
So what is the correct TypeScript way to provide default values for properties inside an object argument?
Short Answer
By the end of this page, you will understand how default values work for object parameters in TypeScript, why defaults cannot be written inside a type definition, and the best patterns to use instead. You will also learn when to use destructuring defaults, nullish coalescing, and fallback assignment safely.
Concept
In TypeScript, types describe shape, but they do not create runtime values.
That is the key idea behind this question.
When you write a type like this:
{ firstName: string; lastName?: string }
TypeScript is only saying:
firstNamemust exist and be a stringlastNameis optional- if
lastNameexists, it must be a string
It is not saying what value lastName should get if it is missing.
A default value such as 'smith' is a runtime behavior, not a type rule. That is why this does not work:
function sayName(params: { firstName: string; lastName: string = 'smith' }) {
Type annotations cannot contain executable default assignments.
Why this matters
In real programs, object parameters are common for:
Mental Model
Think of a TypeScript type as a form template and a default value as a person filling in a blank space.
- The type says which blanks exist and what kind of values are allowed.
- The default value is the action of filling in a blank if the user leaves it empty.
So:
- Type: "There may be a
lastNamefield. If it exists, it must be a string." - Default: "If no
lastNamewas provided, use'smith'."
The template itself does not fill in the value. Your runtime code does.
Another way to think about it:
- TypeScript types are like blueprints
- Defaults are like construction decisions made while building
The blueprint does not install the door. The builder does.
Syntax and Examples
Basic object parameter with an optional property
function sayName(params: { firstName: string; lastName?: string }) {
const lastName = params.lastName ?? 'smith';
const name = firstName + lastName;
}
The problem above is that firstName is not defined as a local variable. A corrected version is:
function sayName(params: { firstName: string; lastName?: string }) {
const lastName = params.lastName ?? 'smith';
const name = params.firstName + lastName;
alert(name);
}
Preferred approach: destructuring with a default
function sayName(
{ firstName, lastName = 'smith' }: { firstName: string; lastName?: string }
) {
const name = firstName + lastName;
alert(name);
}
({ : });
({ : , : });
Step by Step Execution
Consider this version:
type SayNameParams = {
firstName: string;
lastName?: string;
};
function sayName({ firstName, lastName = 'smith' }: SayNameParams) {
const fullName = firstName + ' ' + lastName;
console.log(fullName);
}
sayName({ firstName: 'bob' });
What happens step by step
1. The function is called
sayName({ firstName: 'bob' });
The argument object contains:
{ firstName: 'bob' }
2. Parameter destructuring runs
This part of the function executes:
{ firstName, lastName = 'smith' }
TypeScript/JavaScript extracts properties from the object:
Real World Use Cases
Object parameter defaults are very common in real software.
1. Function options objects
type RequestOptions = {
method?: string;
timeout?: number;
};
function makeRequest(url: string, { method = 'GET', timeout = 5000 }: RequestOptions = {}) {
console.log(url, method, timeout);
}
Used in:
- HTTP helpers
- database query functions
- file operations
2. UI component props
type ButtonProps = {
label: string;
color?: string;
};
function renderButton({ label, color = 'blue' }: ButtonProps) {
console.log(`Button: ${label}, color: ${color}`);
}
Used in:
Real Codebase Usage
In real codebases, developers usually avoid manually mutating incoming parameter objects unless there is a strong reason.
Common pattern: destructure at the function boundary
type Options = {
retry?: number;
verbose?: boolean;
};
function runTask({ retry = 3, verbose = false }: Options = {}) {
if (verbose) {
console.log(`Retry count: ${retry}`);
}
}
This is popular because:
- defaults are visible immediately
- local variables are easy to use
- the original object stays unchanged
Pattern: merge defaults with user options
Useful when many options exist.
type Config = {
host?: string;
port?: number;
secure?: boolean;
};
function connect(config: Config) {
finalConfig = {
: ,
: ,
: ,
...config,
};
.(finalConfig);
}
Common Mistakes
1. Trying to put a default inside a type annotation
This is invalid:
function sayName(params: { firstName: string; lastName: string = 'smith' }) {
}
Why it fails:
- type annotations describe types only
- they cannot run code or assign values
2. Using || when ?? is safer
Broken logic:
function greet({ lastName }: { lastName?: string }) {
const value = lastName || 'smith';
console.log(value);
}
If lastName is '', the result becomes 'smith'.
Safer:
function greet({ lastName }: { lastName?: }) {
value = lastName ?? ;
.(value);
}
Comparisons
| Approach | Example | Best for | Notes |
|---|---|---|---|
| Destructuring default | function f({ name = 'x' }: T) | Clean parameter handling | Usually the best choice |
| Nullish coalescing | const name = obj.name ?? 'x' | Defaults inside function body | Preserves valid falsy values |
| Logical OR | `const name = obj.name | 'x'` | |
| Object spread defaults | const final = { ...defaults, ...options } | Many option fields | Great for config objects |
|| vs ??
Cheat Sheet
Defaulting object properties in TypeScript
Type with optional property
type Params = {
firstName: string;
lastName?: string;
};
Best pattern: destructuring default
function sayName({ firstName, lastName = 'smith' }: Params) {
console.log(firstName, lastName);
}
Alternative: ?? inside function
function sayName(params: Params) {
const lastName = params.lastName ?? 'smith';
console.log(params.firstName, lastName);
}
Default the whole object too
function sayName() {
.(firstName, lastName);
}
FAQ
Can I set a default value directly in a TypeScript type?
No. Types only describe allowed shapes. They do not assign runtime values.
What is the best way to default an optional object property in TypeScript?
Usually, destructuring with a default is the cleanest option:
function f({ name = 'Anonymous' }: { name?: string }) {}
Should I use || or ?? for fallback values?
Use ?? when you only want the fallback for null or undefined. Use || only when all falsy values should trigger the fallback.
Why must lastName be optional if I give it a default?
Because callers may omit it. The type must reflect that by using lastName?: string.
Can I default the whole parameter object too?
Yes:
function f({ name = 'Anonymous' }: { name?: } = {}) {}
Mini Project
Description
Build a small TypeScript utility that formats a user profile from an options object. This project demonstrates how to accept an object parameter, mark some properties as optional, and apply default values safely without mutating the original input.
Goal
Create a function that prints a formatted user profile using sensible defaults for missing optional properties.
Requirements
- Define a type for the user profile options object.
- Require a
firstNameproperty. - Make
lastName,role, andisActiveoptional. - Apply default values for missing optional properties.
- Return a formatted string such as
Bob Smith - Admin (active). - Do not mutate the input object.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.
Angular @ViewChild Returning Undefined: Lifecycle, Child Components, and Fixes
Learn why Angular @ViewChild can be undefined, when it becomes available, and how to access child components correctly using lifecycle hooks.