In this lesson we'll see how Ramda's
pathOr functions can be used to safely access a deeply nested property from an object while avoiding the dreaded checks for
undefined at each new property in the desired path.
Here I have two objects representing departments in a company. As you can see, the AccountingDepartment is much more complete with a personnel section which includes a manager, with a first name, last name, title, and salary. The ITDepartment just has the name and location. Our result is the last name of the manager under personnel for the AccountingDepartment, and if I run this, we'll see that I get the last name printed out.
If I change the AccountingDepartment to the ITDepartment, however, my output's going to go away, and if I open my console we can see that's because I have a type error, cannot read property manager of undefined. The problem here is that personnel is not defined in ITDepartment, so we get an exception.
In order to make this a safer operation and avoid this exception, what I could do is I could come in here and take ITDepartment.personnel. I could add a check for that, and if that's truthy, then it will evaluate the next part, so if my ITDepartment now has personnel, but it still doesn't have manager, we'll see I get a type exception again.
What I can do is I can come in here and then I can add another check for ITDepartment.personnel.manager, and another double ampersand, and I'll get back undefined. At least I'm not getting the exception anymore, but the problem here is if I want to be able to do the same thing with the AccountingDepartment, now I need to take all these checks and basically duplicate them for the accounting department. I could take this and I could wrap this all up in a function that would work on anything with this particular path, but there's a better way.
What I'm going to do, is I've included Ramda in this file, so I'm just going to use destructuring to pull in some functions. I'm going to start with path, and then on my result what I can do is actually call a function that I'm going to create using path, so we're going to call it getManagerLast.
I'm going to use Ramda's path, and path is going to take two arguments. It's going to take an array of property names, and those property names are going to be the properties that we are calling with our path here.
We're going to do personnel, followed by manager, followed by whole name. Now getManagerLast, because it's a curried function, is going to return a new function that's waiting for its second argument. In our case that second argument is going to be the object that we want to get that value from. I'm going to come down here and I'm going to call getManagerLast and I'm going to pass it ITDepartment, and I can get rid of the rest of this. We'll see that I get back undefined.
I didn't have to do all those checks. The property still doesn't exist in ITDepartment, but it's doing what it's supposed to do. If I switch this back to the AccountingDepartment, we'll see that we get the expected value. Now this operation is much safer. I've avoided the error, but I don't necessarily want to get undefined. From passing in the ITDepartment it's great that the exception doesn't get thrown anymore, but I want a value here.
What I can do is I can just use || to say or, and if it's not a truthy value I can just say nobody, and that works, or I could make this part of my getManagerLast function. What I can do is I can take this out of here, get rid of those double pipes, and I can pull in another function from Ramda called pathor. Pathor is going to take my array as a path, but before that, it's going to take a default value. I'll pass in my nobody string, followed by my array.
I'll get back a function I can pass an object to, and it will either get the item on the path, like the AccountingDepartment where I get my value, or it will get undefined and replace it with that default value.