Skip to Content
Course content

230: Rest Parameters and Rest Arguments Typing

Click on the "Edit" button in the top corner of the screen to edit your slide content.

How do I type a function that takes an unknown number of arguments?

In JavaScript, you're probably used to the ...args syntax. In TypeScript, the most important thing to realize is that the "rest" parameter is always treated as an array. So, if you want a function to accept any number of numbers, you don't type the rest parameter as a number; you type it as number[].

I usually run into this when building utility functions, like a calculator that needs to sum up a list of prices. Here is how you'd handle that:

function sumAll(...prices: number[]): number {
  return prices.reduce((acc, current) => acc + current, 0);
}

sumAll(10, 20);          // Works
sumAll(10, 20, 30, 40);  // Also works
sumAll(10, "20");        // Error: Argument of type 'string' is not assignable to parameter of type 'number'.

One quick tip: the rest parameter must be the last parameter in the function signature. You can't have anything coming after it, otherwise TypeScript (and JavaScript) will throw a fit.

What if I need one specific argument first, followed by a bunch of others?

This is a very common pattern. You might have a "header" or "config" argument, and then a variable list of items to process. You just define your required parameters first, and put the rest parameter at the end. TypeScript is smart enough to know that the first argument belongs to the first named parameter, and everything else gets bundled into the array.

Take a look at this example where I'm building a simple logger that takes a category and then a variable number of messages:

function logEvent(category: string, ...messages: string[]) {
  console.log(`[${category}]`);
  messages.forEach(msg => console.log(`- ${msg}`));
}

logEvent("Auth", "User logged in", "Token refreshed", "IP verified");
// category = "Auth"
// messages = ["User logged in", "Token refreshed", "IP verified"]

I personally find this much cleaner than forcing the caller to wrap their arguments in an array manually.

Can I restrict the rest parameters to a specific sequence or a limited number of types?

Standard arrays (like string[]) are great for "any number of the same type," but sometimes you need more precision. If you want the rest parameters to follow a specific pattern, you can use a Tuple with a rest element.

Let's say you're writing a function to update a database record. You want the first argument to be the ID (number), the second to be the field name (string), and then any number of values to update (which could be anything). You can do this:

type UpdateArgs = [id: number, field: string, ...values: any[]];

function updateRecord(...args: UpdateArgs) {
  const [id, field, ...rest] = args;
  console.log(`Updating record ${id} in field ${field} with values: ${rest}`);
}

updateRecord(101, "profile", "John", "Doe", "Developer"); // Valid
updateRecord("101", "profile"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.

By using a tuple as the type for the rest parameter, you've essentially created a "schema" for your function arguments. It's a powerful way to keep your API strict while still remaining flexible.




📋 Practical Task

Exercise: Building a Flexible Expense Report Generator

You are building a financial tool that generates expense reports. You need to create a function called generateReport that accepts the following:

  • A reportName (string) as the first argument.
  • A currency (string) as the second argument.
  • A variable number of amounts (numbers) as the rest parameters.

Requirements:

  1. Type the function so that it rejects any non-number values in the amounts section.
  2. The function should return a string in this format: "Report: [name] | Total: [sum] [currency]".
  3. Use the .reduce() method to calculate the sum of the amounts.

Starter Code:

function generateReport(reportName: string, currency: string, ...amounts: number[]) {
  // Your code here
}

// Test cases
console.log(generateReport("Travel", "USD", 100, 50, 25)); // Should print: "Report: Travel | Total: 175 USD"
console.log(generateReport("Office", "EUR", 10, 20));      // Should print: "Report: Office | Total: 30 EUR"
Rating
0 0

There are no comments for now.

to be the first to leave a comment.