Skip to content

Instantly share code, notes, and snippets.

@gemmadlou
Last active April 13, 2018 22:29
Show Gist options
  • Select an option

  • Save gemmadlou/5fefee68a569a2b4830e733d9b3f9f87 to your computer and use it in GitHub Desktop.

Select an option

Save gemmadlou/5fefee68a569a2b4830e733d9b3f9f87 to your computer and use it in GitHub Desktop.
Partial Application Saves The Day

Partial Application Saves The Day

The Problem

I want to return errors in Javascript, and not throw them. This is the pure functional way. However, Javascript is not a pure functional programming language. Even if I anticipate some errors, run-time errors might creep in. Take this example.

let person = args = ({ name: args.name })

Now, when I want to create a new person, I simply do:

person({ name: 'Gemma' }):

// > {name: "Gemma"}

Excellent. But there's one problem. What if I don't pass in an object. What if I do this:

person();

Oh no! I get an error that now breaks my app! It doesn't return anything either.

The solution

Partial application is one way to pre-load a function. But what we want is to preload a function that can try-catch any errors we have when I try to create a person.

let tryCatch = fn => args => {
  try {
    return fn(args);
  } catch (e) {
    return new Error(e)
  }
}
  1. This function takes a first argument, which it expects to be a function:
tryCatch(person);
  1. This then returns another function.
// > args => {
// >  try {
// >    return fn(args);
// >  } catch (e) {
// >    return new Error(e)
// >  }
// > }
  1. So we have to call that returned function, but this time with our arguments:
tryCatch(person)({ name: 'Gemma' })

Thankfully it returns with our new person. However, what if though we don't provide any arguments. Surely this breaks our app?

tryCatch(person)()

Nope! It returns our error object instead of throwing an Uncaught TypeError

Error: TypeError: Cannot read property 'name' of undefined
    at tryCatch (<anonymous>:9:12)
    at <anonymous>:13:1

Final code

export const TryCatch = fn => args => {
    try {
        return Either.Right(fn(args));
    } catch (e) {
        return Either.Left(new Error(e));
    }
}

I know it's tied, but I don't need so much decoupling

Usage

let person = args = ({ name: args.name })

let setPerson = TryCatch(person);

setPerson({ name: 'Gemma' })
   .fold(val => val, err => err);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment