DEV Community

Cover image for RamdaJS: Using it for the first time
Robbie
Robbie

Posted on • Updated on

RamdaJS: Using it for the first time

Ramda is a JavaScript library that I know for a while but have never used before. Now that I want to use it in my projects, I will write about my experiences with it in some blog posts. And in this article I will describe my first experience with the library. But first things first:

What is Ramda

Ramda describes itself as follows:

“A practical functional library for JavaScript programmers.”

Well that covers already a lot I think. It’s a toolset like the popular lodash but in a more functional style:

  • It embraces immutable data and pure functions
  • All functions are curried automatically

So it’s especially useful if you want to do functional programming in JavaScript (or TypeScript).

Using Ramda for the first time

Ramda was one of those libraries on my list to check out. So I included it in a React project where my main goal was to play with some new tools (I plan to write some blogs about this “test” project as well). The Ramda functions I used the most during this project were:

pipe

I think it's clear what the pipe function does for everyone that is into functional programming: it performs left-to-right function composition.

const isNotEmpty = R.pipe(R.isEmpty, R.not);
Enter fullscreen mode Exit fullscreen mode

And of course Ramda also has a compose function which does the right-to-left function composition.

const isNotEmpty = R.compose(R.not, R.isEmpty);
Enter fullscreen mode Exit fullscreen mode

These two functions are simply indispensable in a library that describes itself as functional.

cond

You can use the cond function as an alternative for if-else constructions. In my test project I used it to create a function that will call the correct error handler based on the given error:

// Function to check if an error has a certain code
const hasErrorCode = (code: string) => R.allPass([
  isPlainObject, R.has('code'), R.propEq('code', code),
]);

// Condition statement which will call the correct error handler
const errorHandler = R.cond([
  [
    hasErrorCode('NotAuthorizedException'),
    ({ code }) => {
      // Handle "NotAuthorizedException"
    },
  ],
  [
    hasErrorCode('UserNotFoundException'),
    ({ code }) => {
      // Handle "UserNotFoundException"
    },
  ],
  [
    R.T, // Functions that always returns true
    () => {
      // Error handler fallback
    },
  ],
]);

// Call error handler
errorHandler(error);
Enter fullscreen mode Exit fullscreen mode

Looks pretty clean, right? Imagine writing this with if-else statements...

tryCatch

If you don't like to have try... catch... statements in your code like me than this function will really help you. It's more of a wrapper around try catch statements which accepts two functions: a tryer and a catcher. When the tryer does not throw an error the result of the tryer will be returned. On the other hand, if the tryer does throw an error the catcher will be called and it's result will be returned. For example:

// In plain JavaScript you will have something like this
let result; // Ugh, we must use let here

try {
  result = mayThrowAnError();
} catch(error) {
  result = null;
}

// In Ramda with tryCatch you can do this
const result = R.tryCatch(
  () => mayThrowAnError(),
  R.always(null),
)();
Enter fullscreen mode Exit fullscreen mode

In my opinion much cleaner and you don't have to use let 🎉

propEq

A simple function that checks if a property of an object is equal to the given value.

// Find a person where name = "Robbie"
const person = persons.find(R.propEq('name', 'Robbie'));
Enter fullscreen mode Exit fullscreen mode

And yes, this can also be easily done in plain JavaScript too:

// Find a person where name = "Robbie"
const person = persons.find(x => x.name === 'Robbie');
Enter fullscreen mode Exit fullscreen mode

The question is: what is more readable? I guess you can discuss that.

Conclusion

Ramda offers a lot of helpful functions for functional programming and function composition. It helps (not enforce) you to write functions without side-effects (pure) and use immutable data. So if you think these concepts are important in good code (you should, in my opinion) it’s definitely a library to check out. It has great power, but….

  • Don’t over use it. Sometimes just plain JavaScript is better or clearer. A good software developer always keeps the readability of code in mind. Maybe you can write the most complex things with Ramda but you should always ask yourself:

Will it be easy for my colleague to read this code and understand directly what’s happening?

For example, you can debate about what is more readable:

// A function that accepts a string and checks if it's not in an array

// Using Ramda
const notInArray = R.pipe(R.flip(R.includes)(array), R.not);

// Using plain JavaScript
const notInArray = code => !array.includes(code);
Enter fullscreen mode Exit fullscreen mode
  • It’s big and has a lot of functions. It will take some time to familiarize yourself with all of them. I probably have missed a lot of powerful functions I could use in my first project. However you will also notice, when you start using Ramda, that you will instinctively think:

“Uhm there is probably a Ramda function for this.”

To learn all the possibilities you should just include it in your project and you will learn it along the way.

  • TypeScript and Ramda…. First of all I must note that I’m not the biggest TypeScript expert so that has to do with it too. But in my first project I had some problems with return types that where incorrectly or not automatically set. Which is a pain because you know the function works but the compiler is complaining. An example of a problem that I had with TypeScript and Ramda:
// This will cause an error
return pipe(
  R.reject<NonNullable<Item>>(R.propEq('id', item.id)),
  R.append(item), // TypeScript error: No overload matches this call.
)(items);

// Turns out you have to tell the reject function that it's dealing with an array
return pipe(
  R.reject<NonNullable<Item>, 'array'>(R.propEq('id', item.id)),
  R.append(item),
)(items);
Enter fullscreen mode Exit fullscreen mode

All problems with TypeScript and Ramda seems "fixable", so again this may be more of an issue related to my TypeScript knowledge than related to Ramda itself.

More about Ramda

Ramda is a very popular library and so there is enough to read about it. An overview of some great articles can be found here or check out the documentation right away and try it out!

Something else…

This is my first post on dev.to. I hope someone is going to read it and it would be awesome if it’s in some way useful to someone. In the future I want to write more posts and they will probably go about JavaScript and related frameworks/libraries. If you have any questions about this post or Ramda in general, please let me know. And of course, I would also like to hear if you have any tips for me about Ramda or about writing posts on dev.to.

Cheers

Top comments (3)

Collapse
 
rasouza profile image
Rodrigo Souza • Edited

Great post! One thing that still is not clear for me is how you organize side-effects inside a FP like Ramda. Can you show us how your code will be making an HTTP request with axios for example?

Collapse
 
batterie profile image
Battery

It was useful indeed. I just started learning functional programming and was introduced to ramda by a more senior dev I work with.

This article helped me getting a better sight of what it looks like in practice while your impressions and experiments with it were very effective on exemplifying and documentating the lib usage.

Good stuff :^)

Collapse
 
fyodorio profile image
Fyodor

Great post 👍 it was interesting to see some real world examples of Ramda usage