-1

How do I read and interpret the following line of a function:

const canUser = (permission) => (permissions) => (guideSlug) => {

This is the full function:

const canUser = (permission) => (permissions) => (guideSlug) => {
  if (!permissions) return false;

  const globalPermissions = permissions['*'] || {};
  const guidePermissions = permissions[guideSlug] || {};
  return globalPermissions[permission] || guidePermissions[permission] || false;
};

Edit

If I have an object like this:

export const checks = {
  canInvite: canUser('invite'),
}

I'm importing canInvite into my component and then running that function, giving it a guideSlug (string) to run the function. It works and checks out, I'm just not entirely sure how to understand what this does from the const canUser function definition

Any clarity here would be helpful. Thanks!

Zack Shapiro
  • 6,648
  • 17
  • 83
  • 151
  • What you're asking about is known as "currying" / "curried functions", in case that gives you a better jumping-off point in terms of research. Perhaps this is a good start: [What is 'currying'?](https://stackoverflow.com/questions/36314/what-is-currying/36321) – Tyler Roper Apr 09 '19 at 17:53
  • Thanks, I wasn't sure if this was currying or not. – Zack Shapiro Apr 09 '19 at 17:57
  • So it looks to me like the first function generates a single permission, then passes the single permission's value to the next function which I assume holds all permissions, that are then passed to the guideslug. It looks confusing to me as well, but I believe this is the logic. This is called a curried function. I don't have a lot of experience with them, but this should help you: https://medium.com/javascript-scene/curry-and-function-composition-2c208d774983 – Ernie Apr 09 '19 at 17:59

2 Answers2

1

const foo = function(x) { return x + 1 } can be loosely written as const foo = x => x + 1. The latter is called an arrow function

So

const canUser = (permission) => (permissions) => (guideSlug) => {
  if (!permissions) return false;

  const globalPermissions = permissions['*'] || {};
  const guidePermissions = permissions[guideSlug] || {};
  return globalPermissions[permission] || guidePermissions[permission] || false;
};

is same as

const canUser = function(permission) {
  return function(permissions) {
    return function (guideSlug) {
      if (!permissions) return false;

      const globalPermissions = permissions['*'] || {};
      const guidePermissions = permissions[guideSlug] || {};
      return globalPermissions[permission] || guidePermissions[permission] || false;
    }
  }
};

This is called partial application or currying, both are kinda same I'm not sure which is the accurate term here.

Here's a case where it's useful...

const foo = (x, y) => { /* something to be done with x and y */ }
let x = foo(a,b);
let y = foo(a,c);
let z = foo(a,d);

Here as you can see there's a lot as in the code which is kinda repetitive and less readable. Writing it in the following way solves the problem...

const foo = x => y => { /* something to be done with x and y */ }
let fooA = foo(a); // fooA is the `y => {}` function with `x = a` "partially applied"
let x = fooA(b);
let y = fooA(c);
let z = foo(a)(d); // you can still write it like this

Another advantage of such pattern is that you can pass around fooA to other function or if you want to store it in an abstraction of a like const somethingRelevantToA = { foo: foo(a), bar: "some other prop ofa" }.

Also you are reusing the logic if you want something like fooA and fooB and they have something in common like...

const foo = x => y => {
  /* piece of code independent of x (this is being reused) */
  /* piece of code dependent only on y or x and y both */
}

So basically instead of writing fooA and fooB separately you are writing foo and thus reusing the logic.

Devansh J
  • 4,006
  • 11
  • 23
0

That piece of code can be rewritten in ES5 like this:

var canUser = function canUser(permission) {
  return function (permissions) {
    return function (guideSlug) {
      if (!permissions) return false;
      var globalPermissions = permissions['*'] || {};
      var guidePermissions = permissions[guideSlug] || {};
      return globalPermissions[permission] || guidePermissions[permission] || false;
    };
  };
};

This is called currying. Which, as state in this article, is the process of taking a function with multiple arguments and turning it into a sequence of functions each with only a single argument.

Assuming you have permissions and guideSlug defined somewhere,

var permissions = {'accounts':{'invite': true}, '*':{'home': '/'}};
var guideSlug = 'accounts';

You could call the function with:

canUser('invite')(permissions)(guideSlug)

var permissions = {'accounts':{'invite': true}, '*':{'home': '/'}};
var guideSlug = 'accounts';

var canUser = function(permission) {
  return function(permissions) {
    return function (guideSlug) {
      if (!permissions) return false;

      var globalPermissions = permissions['*'] || {};
      var guidePermissions = permissions[guideSlug] || {};
  console.log(globalPermissions);
console.log(guidePermissions);
      return globalPermissions[permission] || guidePermissions[permission] || false;
    }
  }
};

console.log(canUser('invite')(permissions)(guideSlug));

One thing I noticed in your example is that it calls only the first function, which means it will return a function back to checks.canInvite when you call it here:

export const checks = {
  canInvite: canUser('invite'),
}
Elder
  • 1,475
  • 9
  • 17