A creative way to have required arguments in JavaScript
Tags: javascript, node, security, typescript
Published: 2021-03-25 01:01:45

Have you ever received an error because you forgot to pass an argument to the function? This is a common situation.

Unfortunately, **JavaScript does not require passing parameters that have been declared in the function,** and **this results in a possible later error.**

Let's see an example. Consider we've got a function that must receive a string and return if that string contains de letter "G".

<small>file.js</small>
```js
function includesG(string) {
  return string.includes('G')
}

console.log(includesG('Gabriel Rufino')) // true
```

This works fine! But there's a problem: what happens if I call the function `includesG` without an argument?

<small>file.js</small>
```js
function includesG(string) {
  return string.includes('G')
}

console.log(includesG())
```

Let's execute using Node:
```bash
$ node file.js
/home/gabrielrufino/Desktop/file.js:2
  return string.includes('G')
                ^

TypeError: Cannot read property 'includes' of undefined
    at includesG (/home/gabrielrufino/Desktop/lab/lab.js:2:17)
    at Object.<anonymous> (/home/gabrielrufino/Desktop/lab/lab.js:5:13)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47
```

It seems to be a pretty violent error 😅

There's a much better way to report the absence of an argument to the developer: **we can combine the power of the default params with the throw of a more descriptive error.**


Let's do it step by step. First, we define the function responsible for throw the error. I'm gonna call it `isRequired`.

<small>file.js</small>
```js
function isRequired(argument) {
  throw new Error(`The argument ${argument} is required`)
}

function includesG(string) {
  return string.includes('G')
}

console.log(includesG())
```

The function `isRequired` is nothing more than a function that throws a custom error based on the name of the argument.

Now that we have this function, **we can use it as the default param of the required argument or arguments**.

Wait for it...

<small>file.js</small>
```js
function isRequired(argument) {
  throw new Error(`The argument ${argument} is required`)
}

function includesG(string = isRequired('string')) {
  return string.includes('G')
}

console.log(includesG())
```

Now, always we forget to pass the argument `string`, the default value will be assumed and the default value is the throw of an error.

Let's run the code:

```bash
$ node file.js
/home/gabrielrufino/Desktop/file.js:2
  throw new Error(`The argument ${argument} is required`)
  ^

Error: The argument string is required
    at isRequired (/home/gabrielrufino/Desktop/lab/lab.js:2:9)
    at includesG (/home/gabrielrufino/Desktop/lab/lab.js:5:29)
    at Object.<anonymous> (/home/gabrielrufino/Desktop/lab/lab.js:9:13)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47
```

And now, we've got a more descriptive error saying that we forgot the parameter `string`.

> "Ok, Gabriel! But don't we replace one error with another? How does it help me?"

Errors were created to help us! They must tell us what specifically is wrong. The first error doesn't help us to find out what is the problem, it only says that the value `undefined` doesn't have the method `includes`. It's so much generic to find the problem. The error we've created says explicitly that we forgot the argument 😄

Thank you!