The short answer
Give the rest parameter a @param tag whose type starts with three dots, {...number}. Inside the function the parameter is a number[]:
/**
* @param {string} sku
* @param {...number} quantities
* @returns {{ sku: string, total: number }}
*/
export function receiveStock(sku, ...quantities) {
const total = quantities.reduce((sum, quantity) => sum + quantity, 0);
return { sku, total };
}
receiveStock("LAMP-01", 4, 2, 6);
/** @type {number[]} */
const deliveries = [12, 8];
receiveStock("DESK-02", ...deliveries);export function receiveStock(sku: string, ...quantities: number[]): { sku: string; total: number } {
const total = quantities.reduce((sum, quantity) => sum + quantity, 0);
return { sku, total };
}
receiveStock("LAMP-01", 4, 2, 6);
const deliveries: number[] = [12, 8];
receiveStock("DESK-02", ...deliveries);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} The last call spreads deliveries into the rest parameter. Spreading an array is fine here, because a rest parameter accepts any number of arguments.
Why it works
{...number} is JSDoc’s variadic form: “zero or more arguments, each a number”. On a rest parameter TypeScript turns it into the array type the function actually receives, so quantities.reduce is checked like any other array method. @param {number[]} quantities means the same thing on a rest parameter; use whichever reads better to your team.
The same thing in TypeScript
The TypeScript equivalent tab writes ...quantities: number[]. TypeScript has no ...number spelling; the dots stay on the parameter and the type is always the array.
What goes wrong
Each argument is checked against the element type, so one wrong value fails with TS2345:
/**
* @param {string} sku
* @param {...number} quantities
* @returns {number}
*/
export function receiveStock(sku, ...quantities) {
return quantities.reduce((sum, quantity) => sum + quantity, 0);
}
receiveStock("LAMP-01", 4, "2");error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Spreading the other way, an array into a function with a fixed number of parameters, fails unless the checker knows the array’s length:
/**
* @param {number} x
* @param {number} y
* @returns {string}
*/
function moveTo(x, y) {
return `translate(${x}px, ${y}px)`;
}
const origin = [0, 0];
moveTo(...origin);error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
/** @type {[number, number]} */
const corner = [120, 80];
moveTo(...corner);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} const origin = [0, 0] is a number[], which could hold any number of values, so tsc cannot promise that moveTo gets exactly two (TS2556). Typing the array as a tuple, [number, number], fixes the length, and the second call passes.
Gotchas
- One rest parameter, and it comes last. That is JavaScript’s rule; TypeScript only adds the type.
- A tuple type describes the whole argument list.
@param {[string, ...number[]]} argson...argsmeans “a string, then numbers”. Do not add the dots there:{...[string, number]}means every argument is a[string, number]pair. argumentsis looser. A.jsfunction that readsargumentsaccepts extra arguments of any type in TypeScript 5.9; TypeScript 7.0 dropped that, so prefer a typed rest parameter.
Questions
Should I write {...number} or {number[]} for a rest parameter?
Either works on a rest parameter: TypeScript 5.9 reads @param {...number} quantities and @param {number[]} quantities as the same number[]. {...number} says "each argument is a number" in the JSDoc tradition; {number[]} matches what the function receives.
What about a function that reads arguments instead of a rest parameter?
In a .js file, a function body that uses arguments lets callers pass extra arguments, typed any. A rest parameter is better: it has a name and a type, and TypeScript 7.0 no longer gives arguments that allowance.
Sources
- JSDoc Reference (@param) · TypeScript handbook
- More on Functions (rest parameters and arguments) · TypeScript handbook
- Rest parameters · MDN Web Docs
Last reviewed 21 October 2026.