Recipe · Functions

How do I type rest parameters (...args) in JSDoc?

  • Node.js (ES modules)
  • @param
  • Rest parameters
  • Spread
  • Checked with TypeScript 5.9

The problem My function takes any number of arguments with ...quantities. What do I write in the @param tag, and why does spreading an array into a normal function fail?

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[]:

stock.js stock.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @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);
A rest parameter typed with @param {...number}.
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:

stock.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: stock.js(11,28): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. stock.js(11,28): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. stock.js(11,28): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. checked 21 October 2026
/**
 * @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'.
Every argument after the first must be a 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:

move.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: move.js(12,8): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. move.js(12,8): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. move.js(12,8): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter. checked 21 October 2026
/**
 * @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);
Spreading an array into fixed parameters.
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[]]} args on ...args means “a string, then numbers”. Do not add the dots there: {...[string, number]} means every argument is a [string, number] pair.
  • arguments is looser. A .js function that reads arguments accepts 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

Last reviewed 21 October 2026.