Better Function Signatures with the Destructuring Assignment

When writing a function sometimes you cannot avoid passing multiple arguments into the function. Lets take a look what is the cleanest way to do this in JavaScript / TypeScript.

Function Declaration

const foo = (a: number, b: number = 12, c: number = 1) => {
  console.log(`${a} ${b} ${c}`);

Function Usage:

// All Arguments set
foo(12, 13, 12);

// Only one optional argument c
foo(12, 12, 12); //b must be declared

// Only mandatory arguments

When you have multiple arguments you run into several problems:

  1. You have to choose which sequence of parameters make the most sense (in this example foo(a, b, c) makes the most sense, however maybe foo(c, b, a) makes more sense - you have to decide)
  2. If you have default values / optional parameters the sequence must change as the optional argument comes last (so lets say a is optional the function is then foo(b,c, a=12)
  3. When using the function you must ensure that the correct sequence is used to get the expected result.
  4. With multiple default/optional arguments - lets say you only have to set the last optional argument, then you still have to set the previous arguments to their default values

Better Declaration with a Destructuring assignment

To make our lives easier it would be much easier to just pass as few arguments as possible. Instead of multiple arguments we just pass a single object. We can access its variables by using the destructuring assignment

const fooModern = (values: { a: number; b?: number; c?: number }) => {
  const { a, b = 12, c = 1 } = values;
  console.log(`${a} ${b} ${c}`);

Writing the function this way does not make it obvious that default values have been set. We can make this more obvious by skipping the variable and directly use the destructuring assignment:

const fooModern = ({ a, b = 12, c = 1 }: { a: number; b?: number; c?: number }) => {
  console.log(`${a} ${b} ${c}`);

With this single object we do not have to take the order of arguments into concideration. The optional/default values can be set in any order.

A call to the function will then look something like this:

// All Arguments set
fooModern({ a: 12, b: 13, c: 12 });

// Only one optional argument c
fooModern({ a: 12, c: 12 });

// Only mandatory arguments
fooModern({ a: 12 });

However in practice you would not be using magic numbers, but first initialize the value with a descriptive variable. Thus you could use shorthand property names - making the code even clearer to read:

const a = 12;
const c = 2;
fooModern({ a, c });

In conclusion in TypeScript/ JavaScript, the cleanest way to write a function with multiple arguments, is to write a function with a single argument that is an object with multiple fields as argument. Thus avoiding all the problems of a multi argument function. You will have to make less decisions how to declare the function and other developers will have it easier to use the function.