DEV Community

Cover image for When to use currying in JavaScript

When to use currying in JavaScript

SlimTim10 on April 12, 2023

This post is about the concept of currying, from functional programming, and when you should use it in JavaScript. I'm going to be honest. You pro...
Collapse
 
pengeszikra profile image
Peter Vivo • Edited

If you add pipeline operators to build, then currying will be much easier because you much cleaner way compose functions together.

userInputEvent 
  |> normalizeEventParameters 
  |> validateInputState 
  |> render
;
Enter fullscreen mode Exit fullscreen mode

which is equal:

render(validateInputState(normalizeEventParameters(userInputEvent)));

just fare more readable.

My luck, for 2 years I can write js fn code with pipeline operator.

Collapse
 
webduvet profile image
webduvet

IMO not necessary to add to language core. It easily can be achieved with transpilers or with library like ramda using traditional syntax.

pipe(fn1, fn2, fn3)(input)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
pengeszikra profile image
Peter Vivo

But ramada give extra weigth to program vs pipelin operator transformed to pure js function call.

Thread Thread
 
webduvet profile image
webduvet

even ramda gives you pure function calls. It's down to optimization. I doubt parsing pipe code through babel would give you any performance boost. But who knows i haven't tried. I have nothing against pipe syntax. If it makes it into specification I will use it.

Collapse
 
joelbonetr profile image
JoelBonetR 🥇

Isn't this an experimental feature in stage 2?

Afaik tou need babel or another tool to "patch" it into a different expression for it to work.

Collapse
 
pengeszikra profile image
Peter Vivo • Edited

You're right, the pipeline operator is just a Stage 2 experimental feature. The science application written in React is quite complex, and Babel is also included in the build system.

.babelrc

{
  "presets": [
    "@babel/preset-react",
    "@babel/preset-typescript"
  ],
  "plugins": [
    [ "@babel/plugin-proposal-pipeline-operator", {"proposal": "minimal"}],
    [ "@babel/plugin-transform-runtime", { "regenerator": true }],
    [ "auto-import", { "declarations": [{ "default": "React", "path": "react" }]}]
  ]
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
pengeszikra profile image
Peter Vivo

in VS code, also need to be set:

"javascript.validate.enable": false

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

Disabling all built-in syntax checking with "javascript.validate.enable": false seems risky.

You'll need to set up a tone of rules in ESLint to validate the rest, all this just to use a single feature that needs to escalate 2 stages more before being implemented.

I'd wholeheartedly suggest avoid using the pipeline operator till it's implemented in the core API (if it does end up like that). In the meantime, you can have a function to handle that pretty easily:

/** Executes Async functions in the order they are passed to, 
sending the input argument as argument for the first function */
export const pipeAsync: any =
  (...fns: Promise<Function>[]) =>
  (initialArg: any) =>
    fns.reduce((currentFunc: Promise<Function>, func: Promise<Function> | any) => 
      currentFunc.then(func), Promise.resolve(initialArg));
Enter fullscreen mode Exit fullscreen mode

It will work for both async and sync operations, though you can have a sync version of it as well, like so:

/** It executes functions in the order they are passed to, 
sending the input argument as argument for the first function */
export const pipe =
  (...functions: Function[]) =>
  (initialArg: any) =>
    functions.reduce((chain, func) => 
      func(chain), initialArg);
Enter fullscreen mode Exit fullscreen mode

Usage example:

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  switch (req.method) {
    case 'GET':
      return pipeAsync(provide, parseData, mock, answer)(req.headers).catch((error: Error) => console.error(error));
    default:
      return res.status(405).end(`Method ${req.method} Not Allowed`);
}
Enter fullscreen mode Exit fullscreen mode

You can learn more about this here:

Best regards 😃

Thread Thread
 
cemkaan profile image
CEM KAAN KÖSALI

or just ust ramda.js

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

Function Composition/Piping and Currying are not the same, tho

Collapse
 
nevodavid profile image
Nevo David • Edited

it's actually very usuful in React...
Here is an example

const doSomething = useCallback((index: number) => () => {
...do something
});
Enter fullscreen mode Exit fullscreen mode

And later:

somevariable.map((_, index) => <div onClick={doSomething(index)} />
Enter fullscreen mode Exit fullscreen mode

I use this concept a lot.

Collapse
 
tracygjg profile image
Tracy Gilmore

Hi SlimTim, In the last few years I have been learning more FP techniques and applying them where appropriate in my JS code. Currying is an important technique to know but I have yet to find an opportunity to employ it. However, I use the associated technique of Partial Application (AP) extensively.
This is a fine discussion of the topic of Currying and I hope you follow it up with one on PA, which I think has far more utility.
Regards, Tracy

Collapse
 
ravavyr profile image
Ravavyr

currying is terrible, pass multiple parameters to your functions, it's literally gonna save you time, money, and your sanity. functions should not return other functions; they should return values, at least in web development.

Collapse
 
caixiangyangcd profile image
CaixiangyangCD

great

Collapse
 
sergeyleschev profile image
Sergey Leschev

Currying is not commonly needed in typical JavaScript codebases. However, where function composition is fundamental, curried functions can be more elegant than the normal practice.

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍