Introduce Parameter Object
When functions have too many parameters, group them into meaningful objects. A simple refactoring that dramatically improves API design.
When a function takes more than 3 parameters, readability drops sharply. The Introduce Parameter Object refactoring groups related parameters into a cohesive object, improving readability, type safety, and extensibility.
The Problem
// ❌ What do these parameters mean at the call site?
function searchProducts(
query: string,
category: string | null,
minPrice: number,
maxPrice: number,
sortBy: string,
sortOrder: 'asc' | 'desc',
page: number,
pageSize: number,
inStock: boolean,
brand: string | null,
): Promise<Product[]> {
// ...
}
// Calling this is a nightmare
const results = await searchProducts(
'laptop', // query
'electronics', // category
500, // min price? max price? who knows
2000, // the other one
'price', // sort by
'asc', // sort order
1, // page
20, // page size
true, // in stock
null, // brand
);
The Refactoring
// ✅ Group related parameters into meaningful objects
interface ProductSearchCriteria {
query: string;
category?: string;
priceRange?: {
min: number;
max: number;
};
brand?: string;
inStock?: boolean;
}
interface SortOptions {
field: string;
order: 'asc' | 'desc';
}
interface PaginationOptions {
page: number;
pageSize: number;
}
interface SearchOptions {
criteria: ProductSearchCriteria;
sort?: SortOptions;
pagination?: PaginationOptions;
}
async function searchProducts(options: SearchOptions): Promise<ProductSearchResult> {
const { criteria, sort, pagination } = options;
// Clean, named access to everything
// ...
}
// The call site is now self-documenting
const results = await searchProducts({
criteria: {
query: 'laptop',
category: 'electronics',
priceRange: { min: 500, max: 2000 },
inStock: true,
},
sort: { field: 'price', order: 'asc' },
pagination: { page: 1, pageSize: 20 },
});
Benefits
1. Self-Documenting Call Sites
Every value has a name. No more guessing what true or 20 means.
2. Optional Parameters Without Ambiguity
// Just omit what you don't need
const results = await searchProducts({
criteria: { query: 'laptop' },
});
3. Easy to Extend
// Adding a new filter? Just add a property — no signature change
interface ProductSearchCriteria {
query: string;
category?: string;
priceRange?: { min: number; max: number };
brand?: string;
inStock?: boolean;
rating?: number; // New!
freeShipping?: boolean; // New!
}
// Zero changes to existing call sites
4. Reusable Types
// The same pagination type works everywhere
interface PaginationOptions {
page: number;
pageSize: number;
}
function searchProducts(opts: { criteria: ProductSearchCriteria; pagination?: PaginationOptions }) { }
function searchUsers(opts: { query: string; pagination?: PaginationOptions }) { }
function searchOrders(opts: { filters: OrderFilters; pagination?: PaginationOptions }) { }
Builder Pattern for Complex Options
When the object itself is complex, combine with a builder:
class SearchBuilder {
private options: SearchOptions = { criteria: { query: '' } };
query(q: string): this {
this.options.criteria.query = q;
return this;
}
category(cat: string): this {
this.options.criteria.category = cat;
return this;
}
priceRange(min: number, max: number): this {
this.options.criteria.priceRange = { min, max };
return this;
}
sortBy(field: string, order: 'asc' | 'desc' = 'asc'): this {
this.options.sort = { field, order };
return this;
}
page(page: number, size: number = 20): this {
this.options.pagination = { page, pageSize: size };
return this;
}
build(): SearchOptions {
return structuredClone(this.options);
}
}
// Fluent, readable API
const results = await searchProducts(
new SearchBuilder()
.query('laptop')
.category('electronics')
.priceRange(500, 2000)
.sortBy('price', 'asc')
.page(1)
.build()
);
Rule of Thumb
- 1-2 parameters: Keep as-is
- 3 parameters: Consider grouping if they’re related
- 4+ parameters: Almost always better as an object
- Boolean flags: Always better named (
{ verbose: true }vstrue)
“The ideal number of arguments for a function is zero.” — Robert C. Martin, Clean Code