# Why use it?

[![Github Repo](https://camo.githubusercontent.com/e83dfdfb23b69cd7cf6e7a77f6500eb4a01c12cc1adc08f3708fc3627f77abe5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6d75736963712f756e777261706974)](https://github.com/musicq/unwrapit)[![npm package](https://img.shields.io/npm/v/unwrapit.svg)](https://npmjs.com/package/unwrapit)

Handling errors is never easy. Let's take a look at 2 cases.

## Unexpected Crashes

It's common to import some functions either written by other teammates or from NPM packages.

```typescript
import {plusOne} from 'lib'
// plusOne(a: number) => number

function handler() {
    const ret = plusOne(1)
    console.log(ret)
}
```

This `handler` function is so simple, yet it still has a chance to cause the program to crash.

How come? Well, based on the signature of `plusOne` we can't find any clue. If we look into the implementation of `plusOne` you'll find that it will throw an error when the given number is even.

```typescript
function plusOne(a: number) {
    if (a % 2 === 0) throw new Error('Given number is even.')
    return a + 1
}
```

Even TypeScript won't give you any hints that the function might throw errors.

You might want to add the return type manually

```typescript
function plusOne(a: number): never | number
```

But the truth is that even if you do this, TypeScript still won't warn you that the code might throw errors. Check the [TS Playground](https://www.typescriptlang.org/play?ssl=7\&ssc=9\&pln=1\&pc=1#code/GYVwdgxgLglg9mABABwDYgM4HkwFMAUAhgFyJggC2ARrgE4CUpeAbnYgD5mU22IDeAKETDEMYIiKIApIgBMiALxLEABnqIoAC1pwA7mVz6AorR218AcgDiMVknLU2MDIlx2AdBfpCRtXFBBaJEJEAGpEAEYBAF8BAQgEDChEP2SFFHRsPHwI7wB6PJFEAD0AfiA).

```typescript
function plusOne(a: number): never | number {
    if (a % 2 === 0) throw new Error('Given number is even.')
    return a + 1
}

const ret = plusOne(1)
//    ^? const ret: number
```

{% hint style="info" %}
If you still don't get it, replace `plusOne` with `JSON.parse`.
{% endhint %}

If we don't read the document carefully, or the document just doesn't mention this trivial and we don't test it out during tests as well, tragedy might happen.

## Try/Catch

Let's take a look at a more complex example

```typescript
import {getUser, getNewsForUser, getRelatedNews} from 'lib'

async function handler(userInfo: {username: string, pwd: string}) {
    let user
    try {
        user = await getUser(userInfo)
    } catch {
        console.error('cannot get user')
        return {err: 'cannot get user')
    }
    
    let news
    try {
        news = await getNewsForUser(user.id)
    } catch {
        console.error('cannot get news for user')
        return {err: 'cannot get news for user')        
    }
    
    let relatedNews
    try {
        relatedNews = await getRelatedNews(news)
    } catch {
        console.error('cannot get related news')
        return {err: 'cannot get related news')     
    }
    
    return {data: {news, relatedNews}}
}
```

In this example, we need to get a lot of data from somewhere, and each step relies on the result of the above step, so they are invoked sequentially.  We also want to provide fine-grained error message hints and return the function whenever an error occurs.

With these 2 problems in the mind, let take a look at how `unwrapit` solve this.

## Just unwrapit!

The idea of [`unwrapit`](https://github.com/musicq/unwrapit) is inspired by [rust](https://www.rust-lang.org/). The concept behind `unwrapit` is simple. Program crashes because of unexpected errors being thrown out, what if we **wrap** them up into a **box**, and then let users **unwrap** them?

Let's take a look at how to improve the above 2 cases by using `unwrapit`

**case 1: unexpected crashed**

```typescript
import {wrap} from 'unwrapit'
import {plusOne} from 'lib'

function handler() {
    const wrappedPlusOne = wrap(plusOne)
    const ret = wrappedPlusOne(1)
    if (!ret.ok) {
        console.error('error occurs', ret.err)
        return
    }
    console.log(ret.value)
}
```

**case 2: try/catch**

{% code lineNumbers="true" %}
```typescript
import {getUser, getNewsForUser, getRelatedNews} from 'lib'
import {wrap} from 'unwrapit'

const wrappedGetUser = wrap(getUser)
const wrappedGetNewsForUser = wrap(getNewsForUser)
const wrappedGetRelatedNews = wrap(getRelatedNews)

async function handler(userInfo: {username: string, pwd: string}) {
    const user = await wrappedGetUser(userInfo)
    if (!user.ok) {
        console.error('cannot get user', user.error)
        return {err: 'cannot get user')
    }
    
    const news = await wrappedGetNewsForUser(user.value.id)
    if (!news.ok) {
        console.error('cannot get news for user', news.error)
        return {err: 'cannot get news for user')  
    }
    
    const relatedNews = await wrappedGetRelatedNews(news.value)
    if (!relatedNews.ok) {    
        console.error('cannot get related news', relatedNews.error)
        return {err: 'cannot get related news')
    }
    
    return {data: {news: news.value, relatedNews: relatedNews.value}}
}
```
{% endcode %}

{% hint style="info" %}
For more usages, just head to **Recipe** section!
{% endhint %}
