Skip to content

Ruairidh Codes

Partial Application and Functional Programming in JavaScript

javascript, functional programming, partial application1 min read

How many times have you heard about making your code 'functional'? You know it makes things more composable, more efficient, and easy to reason with, but what's a practical example of this in action? Something you could use at work?

One technique I like to use in my daily coding is partial application. Wikipedia defines this as:

In computer science, partial application (or partial function application) refers to the process of fixing a >number of arguments to a function, producing another function of smaller arity.

...what?

Put simply, we take a function which could accept multiple inputs, but make it more flexible by splitting it into smaller functions to allow for better reusability. But, it's going to be easier to explain this with some code.

Imagine we have an API call we want to make. We could do something like this:

1const getData = async (url: string) => {
2 try {
3 const response = await fetch(url);
4
5 const result = await response.json();
6 } catch (error) {
7 console.error(error);
8 }
9};

So it works, but if we wanted to then amend our getData function to use another endpoint on the API, we'd need to pass in a whole new URL. It's also not very descriptive. We can do better!

This is where partial application comes in. We can split our function into its constituent parts:

1const getAPIData = (baseUrl: string) => (endpoint: string) => async (
2 callback
3) => {
4 try {
5 const response = await fetch(`${baseUrl}/${endpoint}`);
6 const result = await response.json();
7 callback(result);
8 } catch (error) {
9 console.error(error);
10 }
11};

So what's different? Here we are using currying to allow us to reuse certain elements of the function, making it more efficient. Check out the usage:

1const fetchInternalData = getAPIData("https://internal.myco.io");
2
3// Now we want to fetch employees and clients
4
5const fetchEmployees = fetchInternalData("employees");
6const fetchClients = fetchInternalData("clients");
7
8const callback = (data) => console.log(data); // This could do anything you want. It's just a callback.
9
10// So putting it all together
11
12fetchEmployees(callback);
13fetchClients(callback);
14
15// We can then use the same function for an external API
16
17const fetchExternalData = getAPIData("https://api.github.com");
18
19const fetchUsers = fetchExternalData("/users");
20
21// We want to get the login names here
22fetchUsers((data) => {
23 console.log(data.map((user) => user.login));
24});
25
26// And the avatars here
27fetchUsers((data) => {
28 console.log(data.map((user) => user.avatar_url));
29});

And, that's it! Just a simple way of splitting up a rigid function and making it more composable, saving you and your team from needing to reinvent the wheel. It also is easier to reason with which makes code reviews a more pleasant experience for everyone involved!

P.S. Want to sound clever when you talk about this stuff? You could mention that it reduces the arity of your functions. Put simply, arity is just a fancy way of talking about the number of parameters your function takes. If you've coded for a while, then you'll actually have used this already:

  • A function that takes one parameter is unary
  • A function which takes two parameters is binary
  • A function which takes three parameters is ternary

...and so on.

Thanks to Kyle Shevin who I learned this from on Egghead, and Mark Barry for a neat async refactoring which saved me some time when putting this quick post together.

Subscribe to the Newsletter

Subscribe to get my latest content by email.

    I won’t send you spam.

    Unsubscribe at any time.



    © 2021 by Ruairidh Wynne-McHardy. All rights reserved.