Warning Unexpected unnamed function func-names under, ESLint rule - javascript

My eslint version is 4.18.2, it would give a warning like this:
Unexpected unnamed function
Expected an assignment or function call and instead saw an expression
When defining functions in such a way:
const farmerIds = a.reduce((function (hash) {
return function (prev, curr) {
!hash[curr.farmerId] && (hash[curr.farmerId] = prev.push(curr));
return prev;
};
}(Object.create(null))), []);

These are two different issues…
Unexpected unnamed function
This is, as pointed out by Constantin, the ESLint rule func-names.
If you don't want to disable this rule, you can either use names for your functions, like so:
const farmerIds = a.reduce((function reducer(hash) {
return function fn(prev, curr) {
!hash[curr.farmerId] && (hash[curr.farmerId] = prev.push(curr));
return prev;
};
}(Object.create(null))), []);
Or, and this I would recommend personally, use arrow functions:
const farmerIds = a.reduce(
(hash => {
return (prev, curr) => {
!hash[curr.farmerId] && (hash[curr.farmerId] = prev.push(curr));
return prev;
};
})(Object.create(null)),
[]
);
Expected an assignment or function call and instead saw an expression
ESLint is complaining about this line, which is indeed an expression, not an assignment or function call:
!hash[curr.farmerId] && (hash[curr.farmerId] = prev.push(curr));
You can rewrite it as an if statement:
if (!hash[curr.farmerId]) {
hash[curr.farmerId] = prev.push(curr);
}
Fixing both
Putting the code examples above together, this code should run without ESLint complaining:
const farmerIds = a.reduce(
(hash => (prev, curr) => {
if (!hash[curr.farmerId]) {
hash[curr.farmerId] = prev.push(curr);
}
return prev;
})(Object.create(null)),
[]
);
Note that I've also removed the curly braces around the body of the first arrow function, which is a nice additional feature of arrows to keep the code more concise.

Another simple way is give the underscore as the function name. For example:
const farmerIds = a.reduce((function _(hash) {...}(...);

If we need to export without declaring, it can be used as below
export default () => {
// your code goes here
}

Related

no-return-assign / no-unused-expressions

I have the following line of code working on my code, but eslint is getting me an error back.
this.data.forEach(el => el.value === newValue ? el[column] = newValue[column] : el)
This gives me the following error:
no-return-assign: Arrow function should not return assignment.
In this question it states I would solve the problem by simply surrounding everything after => in curly braces like this:
this.data.forEach(el => { el.value === newValue ? el[column] = newValue[column] : el })
However, this is now causing the following error:
no-unused-expression: Expected an assignment or function call and instead saw an expression.
Any clues on how to solve this?
The reason you're getting these kinds of warnings is because it's confusing to put imperative code inside an expression. Your code is equivalent to something like this, which is much more readable:
this.data.forEach(el => {
if (el.value === newValue) {
el[column] = newValue[column];
return newValue[column];
else {
return el;
}
});
It's worth noting that the return value of a callback in forEach is ignored, so your code actually probably does something different to what you intended. If the assignment statement is all you wanted, you can do this:
this.data
.filter(el => el.value === newValue)
.forEach(el => {
el[column] = newValue[column];
});

How can I add a console log in this function?

Pretty straight forward question, I'm just trying to get a console log in this es6 function.
const testLinesSelector = state => state.tests.testLines || [];
I've tried:
const testLinesSelector = state => {
console.log('INSIDE THE SELECTOR ===> ');
return {state.tests.testLines || [] }
};
Remove the braces in your return statement, like so:
const testLinesSelector = state => {
console.log('INSIDE THE SELECTOR ===> ');
return state.tests.testLines || [];
};
As a side-note, I noticed a lot of ES6 code uses function-variables or function-properties instead of just functions - is there a reason you don’t do this instead?
function testLinesSelector( state ) {
console.log('INSIDE THE SELECTOR ===> ');
return state.tests.testLines || [];
};
Another approach you might consider automating your code using Function.name - though this requires using a named function (a la function foobar() { ... }). There are techniques to get the "name" of an anonymous function or arrow-function in JavaScript but they're more involved and may not be compatible with the "established patterns in the code" you're working with.
But here's how you can do it with named functions:
function annotate( func ) {
return ( ...args ) => {
console.log( func.name ); // `Function.name` is supported in ES6.
return func( ...args );
};
}
const testLinesSelector = annotate( function testLinesSelector( state ) { return state.tests.testLines || [] } );

How can I fix ES6 Eslint errors while trying to return a ternary operator in arrow function?

I understand that () => {} does not need return, however if it is not there then Eslint complains about unused expressions.
export const isInInterval = (from, to, target) => {
if (isNaN(Date.parse(to)) && isNaN(Date.parse(from)) === true) {
return
}
const toUnixTimestamp = time => new Date(time).getTime()
toUnixTimestamp(to) - target > toUnixTimestamp(from) ? true : false
}
Here is the function: it tries to find out whether some specified date(to) minus specified period(target) is later in time than from. It should return true if so and false in the opposite case.
I keep bumping into eslint error expected assignment to a function call and instead saw expression.
I tried to rewrite it several times, but in most iterations I got `arrow function expects no return error, ex.:
return (toUnixTimestamp(to) - target > toUnixTimestamp(from)) ? true : false
I understand that () => {} does not need return
That's not the case. Arrow functions only implicitly return when what followed the => is a single expression. If you use => {, the opening bracket { indicates the start of a function block, and you do indeed need to explicitly return at the end of the block (or wherever else you want to return something).
At the moment, your code isn't returning anything at all - that's what the linting error is trying to tell you - the true : false is going unused at the moment, it's just an orphaned expression.
So, just add the return statement to the beginning of your conditional:
export const isInInterval = (from, to, target) => {
if (isNaN(Date.parse(to)) && isNaN(Date.parse(from)) === true) {
return
}
const toUnixTimestamp = time => new Date(time).getTime()
return toUnixTimestamp(to) - target > toUnixTimestamp(from)
? true
: false
}
Or, because > evaluates to a boolean already, you might omit the conditional operator entirely:
return toUnixTimestamp(to) - target > toUnixTimestamp(from)
Here's an example of how you would write an arrow function that does use implicit return:
export const isEarlyTimestamp = (timestamp) => (
timestamp < 4000000
? true
: false
);
try this:
export const isInInterval = (from, to, target) => {
if (isNaN(Date.parse(to)) && isNaN(Date.parse(from)) === true) {
return false
}
const toUnixTimestamp = time => new Date(time).getTime()
return toUnixTimestamp(to) - target > toUnixTimestamp(from);
}

Reproduce without using spread arguments (...) when passing arguments through to a function call

I have been learning about spread arguments and I found it rather surprising that when using: cur.func.call(null, ...cur.arg, acc), args) that if you have an empty array no argument is passed to add().
Is it possible to reproduce this without using the ... seen in this line of code cur.func.call(null, ...cur.arg, acc), args)
class Lazy {
constructor() {
this.builtUpFuncs = [];
}
add(...newArgs) {
console.info(newArgs)
this.builtUpFuncs.push({
func: newArgs[0],
arg: typeof newArgs[1] === "undefined" ? [] : [newArgs[1]],
});
return this;
}
evaluate(target) {
return target.map((args) =>
this.builtUpFuncs.reduce((acc, cur) =>
cur.func.call(null, ...cur.arg, acc), args)
);
}
}
const lazyClass = new Lazy();
const returnValue =
lazyClass
.add(function timesTwo(a) { return a * 2; })
.add(function plus(a, b) { return a + b; }, 1)
.evaluate([1, 2, 3]);
console.info(returnValue);
If you want to avoid the spread syntax, the traditional way is to use apply instead of call:
cur.func.apply(null, cur.arg.concat(acc))
Note that the args part is the second argument to reduce, not this function call.
In either syntax it is normal that if cur.arg is an empty array, the only argument passed is acc.

Functional Ramda Passing function parameter outside of scope

Take the following example imperative JavaScript example:
getAnimalList = (hasCat) => {
const baseAnimals = { dog: animLib.dog(), bear: animLib.bear()};
if(hasCat){
baseAnimals.cat = animLib.cat();
}
return baseAnimals
}
I am trying to write this code in a functional style with Ramda, but the only way I can do so is by having the functions reach outside of scope:
getAnimalList = (hasCat) => {
const baseAnimals = { dog: animLib.dog(), bear: animLib.bear()};
return when(always(hasCat), merge({hasCat: animLib.cat()}))(baseAnimals)
}
Leaving aside how animLib is outside of scope, the way I would fix has hasCat from being pass from the outside(if this is a problem at all) is the following:
getAnimalList = (hasCat) => {
const baseAnimals = { dog: animLib.dog(), bear: animLib.bear()};
const mergeCat = when(compose(equals(true), prop('hasCat')),
compose(merge({hasCat: animLib.cat()}), prop('baseAnimals')));
return mergeCat({hasCat: hasCat, baseAnimals: baseAnimals});
}
But this makes the code incredibly verbose. Is there a better way to do this? Or is the verbosity just the cost of keeping the code more pure.
It seems to me that this would do fine:
getAnimalList = (animLib, hasCat) => {
const baseAnimals = { dog: animLib.dog(), bear: animLib.bear()};
return hasCat ? merge({hasCat: animLib.cat()}, baseAnimals) : baseAnimals;
}
Because Ramda's when and ifElse are based around predicate functions rather than boolean values, using them seems to be overkill here.
Obviously if you want a version that has animLib in scope, you can curry this function, either with something like Ramda's curry or just by changing to
getAnimalList = (animLib) => (hasCat) => { /* ... */ }
Then you can create newAnimalList = getAnimalList(myAnimLib).

Categories