# wrap

`wrap` can secure your functions. This means even if your functions throw errors, it will still be safe to call them without worrying that they will cause your program to crash.

A simple example of wrapping a synchronous function

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

const tryParseJson = wrap(() => JSON.parse(`{"package": "unwrapit!"}`))
const json = tryParseJson()
if (!json.ok) {
    return json.error
}
console.log(json.value)
```

If you are sure that the wrapped function won't panic anyway, or just for debug usage, you can call `unwrap` method to force unwrap the value.

```typescript
tryParseJson().unwrap()
```

This will unwrap the value without checking whether it will throw an error or not.

You can wrap an asynchronous function as well.

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

const fetchWrapper = wrap(fetch)
const ret = (await fetchWrapper('www.google.com')).unwrap()
const text = await ret.text()
```

{% hint style="info" %}
Note that you need to `await` or call `then` to resolve the Promise result first because we don't know if the function will throw errors or not without executing it.
{% endhint %}

### Type <a href="#asynchronous-function" id="asynchronous-function"></a>

`wrap` will infer the given function type and return it as is except wrapping the return type of the given function into `Result`.

<pre class="language-typescript"><code class="lang-typescript">declare function fn(a: number): string

const f = wrap(fn)
<strong>//    ^? const f: (a: number) => Result&#x3C;string, unknown>
</strong></code></pre>

For asynchronous functions, the return type looks like below

<pre class="language-typescript"><code class="lang-typescript">declare function fn(a: number): Promise&#x3C;string>

const f = wrap(fn)
<strong>//    ^? const f: (a: number) => Promise&#x3C;Result&#x3C;string, unknown>>
</strong></code></pre>

#### Specify Error Type

By default, `wrap` won't know what error type the function is going to throw, so it will infer it as `unknown`, so that you can cast it when you are handling it. However, if you are developing a common function that want to share with others, you probably need to specify the specific error type. With the `wrap` function type definition, you can specify the error type easily.

Let's say we have a function with a signature below

```typescript
declare function fn(a: number): Promise<string>
const f = wrap(fn)
```

It will infer the wrapped type like below

```typescript
const f: (a: number) => Promise<Result<string, unknown>>
```

We want to specify the error type as `Error`. Just do below

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

const f = wrap<Error, typeof fn>(fn)
```

Now the inferred type will be

```typescript
const f: (a: number) => Promise<Result<string, Error>>
```

#### Specify Both Error & Return Type

Sometimes, the function we wrapped may return `any`, we want to narrow down the return type to make it more precise. You may think of casting the function to be wrapped to the desired signature. Well, with `wrap` function type, we can just specify the return type like below

```typescript
declare function fn(a: number): Promise<any>
const f = wrap<Error, typeof fn, Promise<string>>(fn)
//    ^? const f: (a: number) => Promise<Result<string, Error>>
```

{% hint style="info" %}
Note that the given returned type should be a subtype of the function's return type, otherwise, TypeScript will complain.

```typescript
declare function fn(a: number): string
const f = wrap<Error, typeof fn, number>(fn)
//                               ^? Type 'number' does not satisfy the constraint 'string'.
```

{% endhint %}
