Using _ (underscore) variable with arrow functions in ES6/Typescript

JavascriptTypescriptEcmascript 6Arrow Functions

Javascript Problem Overview


I came across this construct in an Angular example and I wonder why this is chosen:

_ => console.log('Not using any parameters');

I understand that the variable _ means don't care/not used but since it is the only variable is there any reason to prefer the use of _ over:

() => console.log('Not using any parameters');

Surely this can't be about one character less to type. The () syntax conveys the intent better in my opinion and is also more type specific because otherwise I think the first example should have looked like this:

(_: any) => console.log('Not using any parameters');

In case it matters, this was the context where it was used:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}

Javascript Solutions


Solution 1 - Javascript

The reason why this style can be used (and possibly why it was used here) is that _ is one character shorter than ().

Optional parentheses fall into the same style issue as optional curly brackets. This is a matter of taste and code style for the most part, but verbosity is favoured here because of consistency.

While arrow functions allow a single parameter without parentheses, it is inconsistent with zero, single destructured, single rest and multiple parameters:

let zeroParamFn = () => { ... };
let oneParamFn = param1 => { ... };
let oneParamDestructuredArrFn = ([param1]) => { ... };
let oneParamDestructuredObjFn = ({ param1 }) => { ... };
let twoParamsFn = (param1, param2) => { ... };
let restParamsFn = (...params) => { ... };

Although is declared but never used error was fixed in TypeScript 2.0 for underscored parameters, _ can also trigger unused variable/parameter warning from a linter or IDE. This is a considerable argument against doing this.

_ can be conventionally used for ignored parameters (as the other answer already explained). While this may be considered acceptable, this habit may result in a conflict with _ Underscore/Lodash namespace, also looks confusing when there are multiple ignored parameters. For this reason it is beneficial to have properly named underscored parameters (supported in TS 2.0), also saves time on figuring out function signature and why the parameters are marked as ignored (this defies the purpose of _ parameter as a shortcut):

let fn = (param1, _unusedParam2, param3) => { ... };

For the reasons listed above, I would personally consider _ => { ... } code style a bad tone that should be avoided.

Solution 2 - Javascript

> The () syntax conveys the intent better imho and is also more type specific

Not exactly. () says that the function does not expect any arguments, it doesn't declare any parameters. The function's .length is 0.

If you use _, it explicitly states that the function will be passed one argument, but that you don't care about it. The function's .length will be 1, which might matter in some frameworks.

So from a type perspective, it might be more accurate thing to do (especially when you don't type it with any but, say, _: Event). And as you said, it's one character less to type which is also easier to reach on some keyboards.

Solution 3 - Javascript

I guess _ => is just used over () => because _ is common in other languages where it is not allowed to just omit parameters like in JS.

_ is popular in Go and it's also used in Dart to indicate a parameter is ignored and probably others I don't know about.

Solution 4 - Javascript

It is possisble to distinguish between the two usages, and some frameworks use this to represent different types of callbacks. For example I think nodes express framework uses this to distinguish between types of middleware, for example error handlers use three arguments, while routing uses two.

Such differentiation can look like the example below:

const f1 = () => { } // A function taking no arguments
const f2 = _ => { }  // A function with one argument that doesn't use it

function h(ff) { 
  if (ff.length === 0) {
    console.log("No argument function - calling directly");
    ff();
  } else if (ff.length === 1) {
    console.log("Single argument function - calling with 1");
    ff(1);
  }
}

h(f1);
h(f2);

This is based off Bergi's answer, but I thought adding an example was a little more editing than I was happy to do to someone elses post.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHaltView Question on Stackoverflow
Solution 1 - JavascriptEstus FlaskView Answer on Stackoverflow
Solution 2 - JavascriptBergiView Answer on Stackoverflow
Solution 3 - JavascriptGünter ZöchbauerView Answer on Stackoverflow
Solution 4 - JavascriptMichael AndersonView Answer on Stackoverflow