DEV Community

kcvgan
kcvgan

Posted on • Edited on

A take on concise promise handling in TypeScript.

After looking for a clean way to handle async/await REST calls without try-catch blocks, I found a small wrapper that satisfied my needs.

The article that inspired me was https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/.

function on (promise) {
    return promise
      .then(response => [response, null)
      .catch(error => [null, error])
}

/// async function
async function doSomething() {
    const [data, error] = await on(somePromise())
    if (data) {
        // do whatever
    } else {
        // handle error
    }
}

The above solution was like an eureka moment after I did started with stuff like this:

promise
    .then(result => doSomething(result))
    .catch(error => log(error))

and this:

    try {
        const data = await somePromise()
        // do whatever
    } catch (e) {
        // handle error
    }

After doing lots of work on the frontend with React and learning hooks, the simplicity of the solution outlined in the article just clicked. During code review however, a colleague pointed out that while nice, it's not typed at all. He then suggested to actually type it properly.

Here it is:

// using Axios but you can type your promises however you'd like
const on = <RES, ERR = any> (promise: AxiosPromise): Promise<[RES | null, ERR | null]> => {
  return promise
    // destructuring since my API returns all the good stuff like so.
    .then(({ data }): [RES, ERR | null] => [data, null])
    .catch((error): [RES | null, ERR] => [null, error])
}

// and now calling it from an async function
const [todo, error] = await on<Todo>(somePromise())
// now my returned todo is already typed as Todo.
// error typing is optional, it defaults to any.

I'm posting my solution just to share my point of view. I'm very open to improvements and comments. Would you use such a solution? Let me know. This is also my first article/post. Since I've always wanted to write about stuff I do, I decided such a short topic might be just enough to get my feet wet.

Cheers!

Top comments (3)

Collapse
 
cubiclebuddha profile image
Cubicle Buddha

It’s a great article, but your approach seems dangerous to me because you don’t have to check the error at all because there’s no requirement to destructive both properties. See below:

const [todo] = await on<Todo>(somePromise())

I mean it’s a cool code sample you wrote, it’s just dangerous. Follow my dev.to channel and I’ll be showing how to use the Either/Optional pattern to accomplish the same things you’re lookig for but in a way that forces you to check the error first.

Collapse
 
kcvgan profile image
kcvgan

It would be possible to simply switch the return order as in [error, todo]. That way you would always return an error and checking whether something happened would be up to you. Another way would be to create an Optional generic object, something along the lines of java optionals or other language monads.
I will follow your channel and await on (🤭) your article!

Collapse
 
cubiclebuddha profile image
Cubicle Buddha

Haha I see what you did there 🤣