Rest parameters in JavaScript
The Short Answer
Rest parameters (...args) collect all remaining arguments passed to a function into a real array. Unlike the legacy arguments object (which is array-like but not an array), rest parameters give you a proper Array instance with all array methods available. They must be the last parameter in the function signature and can only appear once.
Basic Syntax and Usage
The rest parameter syntax uses three dots (...) before the parameter name. It collects any number of arguments into an array. If no extra arguments are passed, the rest parameter is an empty array (never undefined). This makes functions that accept variable numbers of arguments clean and type-safe.
// Rest parameter collects all arguments into an array
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
sum(1, 2, 3); // 6
sum(10, 20); // 30
sum(); // 0 (numbers is [])
// Rest parameter after named parameters — collects the "rest"
function log(level: string, ...messages: string[]): void {
console.log(`[${level}]`, ...messages);
}
log('error', 'Connection failed', 'retrying in 5s');
// [error] Connection failed retrying in 5s
// The rest parameter is always a real Array
function example(...args: number[]) {
console.log(Array.isArray(args)); // true
args.map((n) => n * 2); // Works — it's a real array
args.filter((n) => n > 0); // Works
args.forEach((n) => console.log(n)); // Works
}
Rest Parameters vs the arguments Object
Before ES6, the only way to handle variable arguments was the arguments object — an array-like object available in every function. It has indices and a length but isn't a real array (no map, filter, reduce). Rest parameters replaced it with a cleaner, typed, and more capable alternative. Arrow functions don't even have arguments, making rest parameters the only option there.
// ❌ Old way — arguments object (not a real array, no types)
function oldSum() {
// arguments is array-like: { 0: 1, 1: 2, 2: 3, length: 3 }
// Must convert to array to use array methods
const args = Array.from(arguments);
return args.reduce((total, num) => total + num, 0);
}
// ✅ Modern way — rest parameters (real array, typed)
function newSum(...numbers: number[]): number {
// numbers is already a real Array — use methods directly
return numbers.reduce((total, num) => total + num, 0);
}
// Arrow functions don't have 'arguments' at all
const multiply = (...factors: number[]) => {
// 'arguments' would reference the outer function's arguments (or error)
return factors.reduce((product, factor) => product * factor, 1);
};
| Feature | Rest Parameters | arguments object |
|---|---|---|
| Type | Real Array | Array-like object (no array methods) |
| Arrow functions | Works | Not available |
| TypeScript | Fully typed | Typed as IArguments (limited) |
| Named params | Collects only the 'rest' | Contains ALL arguments |
| Destructuring | Supported | Not directly supported |
| Introduced | ES6 (2015) | ES1 (1997) |
Rest in Destructuring
Rest syntax also works in destructuring assignments — both arrays and objects. In array destructuring, it collects remaining elements. In object destructuring, it collects remaining properties. This is extremely useful for separating known properties from 'everything else' (common in React for forwarding props).
// Rest in array destructuring — collect remaining elements
const [first, second, ...remaining] = [1, 2, 3, 4, 5];
// first = 1, second = 2, remaining = [3, 4, 5]
// Rest in object destructuring — collect remaining properties
const { id, name, ...metadata } = {
id: 1,
name: 'Alice',
role: 'admin',
createdAt: '2024-01-01',
};
// id = 1, name = 'Alice', metadata = { role: 'admin', createdAt: '2024-01-01' }
// Common React pattern — extract known props, forward the rest
type ButtonProps = {
variant: 'primary' | 'secondary';
size: 'sm' | 'md' | 'lg';
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
function Button({ variant, size, ...htmlProps }: ButtonProps) {
return (
<button
className={`btn-${variant} btn-${size}`}
{...htmlProps} // Forward onClick, disabled, aria-label, etc.
/>
);
}
The React prop-forwarding pattern is one of the most common uses of rest in destructuring. You extract the props your component cares about, then spread the rest onto the underlying HTML element. This makes components flexible without explicitly listing every possible HTML attribute.
Rules and Constraints
Rest parameter rules:
- ✅Must be the LAST parameter — function(a, b, ...rest) is valid
- ✅Only ONE rest parameter per function — function(...a, ...b) is a syntax error
- ✅Collects only the remaining arguments — named params before it are excluded
- ✅Always an array — even if no arguments are passed (empty array, not undefined)
- ✅Works in arrow functions (unlike arguments)
Rest vs Spread (Common Confusion)
Rest and spread use the same ... syntax but do opposite things. Rest collects multiple elements into one array (used in function parameters and destructuring). Spread expands an array or object into individual elements (used in function calls, array literals, and object literals). The context determines which operation is happening.
// REST — collects into an array (in parameter position)
function logAll(...items: string[]) { // REST: collects arguments
console.log(items);
}
// SPREAD — expands an array (in argument position)
const fruits = ['apple', 'banana', 'cherry'];
logAll(...fruits); // SPREAD: expands array into individual arguments
// REST in destructuring — collects remaining
const [head, ...tail] = [1, 2, 3, 4]; // REST: tail = [2, 3, 4]
// SPREAD in array literal — expands into new array
const extended = [0, ...tail, 5]; // SPREAD: [0, 2, 3, 4, 5]
// Quick rule:
// Collecting (left side of =, in params) → REST
// Expanding (right side of =, in calls) → SPREAD
Why Interviewers Ask This
This question tests your understanding of modern JavaScript fundamentals. Interviewers want to see that you know the difference between rest and spread (same syntax, opposite operations), understand why rest parameters replaced the arguments object, can use rest in destructuring for prop forwarding, and know the constraints (last parameter, only one). It's a foundational concept that shows up constantly in React patterns.
Quick Revision Cheat Sheet
What it does: Collects remaining arguments into a real Array
Syntax: function fn(a, b, ...rest) — rest is always last, always an array
vs arguments: Real array, works in arrows, typed, collects only remaining args
vs spread: Rest collects (params/destructuring); spread expands (calls/literals)
In destructuring: const { known, ...rest } = obj — collects remaining properties
React pattern: Extract component props, spread ...rest onto the HTML element