Unwrapping Results

Sometimes you need to extract the actual value from a Result, exiting the Result "world" back into plain values. The unwrap and unwrapError functions help with this.

Extracting Success Values with unwrap

The unwrap function extracts the success value from a Result:

import { 
import Result
Result
} from '@praha/byethrow';
const
const result: Result.Result<42, never>
result
=
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42);
const
const value: 42
value
=
import Result
Result
.
const unwrap: <Result.Result<42, never>>(result: Result.Result<42, never>) => 42 (+3 overloads)
unwrap
(
const result: Result.Result<42, never>
result
);
// value: 42

What Happens on Failure?

If the Result is a Failure and no default is provided, unwrap throws the error:

import { 
import Result
Result
} from '@praha/byethrow';
const
const result: Result.Result<never, Error>
result
=
import Result
Result
.
const fail: <Error>(error: Error) => Result.Result<never, Error> (+1 overload)
fail
(new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('Something went wrong'));
const
const value: never
value
=
import Result
Result
.
const unwrap: <Result.Result<never, Error>>(result: Result.Result<never, Error>) => never (+3 overloads)
unwrap
(
const result: Result.Result<never, Error>
result
);
// Throws: Error('Something went wrong')

Providing a Default Value

You can provide a default value to avoid throwing:

import { 
import Result
Result
} from '@praha/byethrow';
const
const result: Result.Result<never, "error">
result
=
import Result
Result
.
const fail: <"error">(error: "error") => Result.Result<never, "error"> (+1 overload)
fail
('error');
const
const value: 0
value
=
import Result
Result
.
const unwrap: <Result.Result<never, "error">, 0>(result: Result.Result<never, "error">, defaultValue: 0) => 0 (+3 overloads)
unwrap
(
const result: Result.Result<never, "error">
result
, 0);
// value: 0 (default value)
import { 
import Result
Result
} from '@praha/byethrow';
const
const success: Result.Result<42, never>
success
=
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42);
const
const value: 42 | 0
value
=
import Result
Result
.
const unwrap: <Result.Result<42, never>, 0>(result: Result.Result<42, never>, defaultValue: 0) => 42 | 0 (+3 overloads)
unwrap
(
const success: Result.Result<42, never>
success
, 0);
// value: 42 (success value, default ignored)

Extracting Error Values with unwrapError

The unwrapError function is the opposite—it extracts the error value:

import { 
import Result
Result
} from '@praha/byethrow';
const
const result: Result.Result<never, "Something went wrong">
result
=
import Result
Result
.
const fail: <"Something went wrong">(error: "Something went wrong") => Result.Result<never, "Something went wrong"> (+1 overload)
fail
('Something went wrong');
const
const error: "Something went wrong"
error
=
import Result
Result
.
const unwrapError: <Result.Result<never, "Something went wrong">>(result: Result.Result<never, "Something went wrong">) => "Something went wrong" (+3 overloads)
unwrapError
(
const result: Result.Result<never, "Something went wrong">
result
);
// error: 'Something went wrong'

What Happens on Success?

If the Result is a Success and no default is provided, unwrapError throws the value:

import { 
import Result
Result
} from '@praha/byethrow';
const
const result: Result.Result<42, never>
result
=
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42);
const
const error: never
error
=
import Result
Result
.
const unwrapError: <Result.Result<42, never>>(result: Result.Result<42, never>) => never (+3 overloads)
unwrapError
(
const result: Result.Result<42, never>
result
);
// Throws: 42

Providing a Default Error

You can provide a default value to avoid throwing:

import { 
import Result
Result
} from '@praha/byethrow';
const
const result: Result.Result<42, never>
result
=
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42);
const
const error: "No error"
error
=
import Result
Result
.
const unwrapError: <Result.Result<42, never>, "No error">(result: Result.Result<42, never>, defaultValue: "No error") => "No error" (+3 overloads)
unwrapError
(
const result: Result.Result<42, never>
result
, 'No error');
// error: 'No error' (default value)
import { 
import Result
Result
} from '@praha/byethrow';
const
const failure: Result.Result<never, "Something went wrong">
failure
=
import Result
Result
.
const fail: <"Something went wrong">(error: "Something went wrong") => Result.Result<never, "Something went wrong"> (+1 overload)
fail
('Something went wrong');
const
const error: "Something went wrong" | "No error"
error
=
import Result
Result
.
const unwrapError: <Result.Result<never, "Something went wrong">, "No error">(result: Result.Result<never, "Something went wrong">, defaultValue: "No error") => "Something went wrong" | "No error" (+3 overloads)
unwrapError
(
const failure: Result.Result<never, "Something went wrong">
failure
, 'No error');
// error: 'Something went wrong' (failure value, default ignored)

Working with Async Results

Both unwrap and unwrapError work with ResultAsync:

import { 
import Result
Result
} from '@praha/byethrow';
const
const asyncResult: Result.ResultAsync<number, never>
asyncResult
=
import Result
Result
.
const succeed: <Promise<number>>(value: Promise<number>) => Result.ResultAsync<number, never> (+1 overload)
succeed
(
var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.
PromiseConstructor.resolve<number>(value: number): Promise<number> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.@returnsA promise whose internal state matches the provided promise.
resolve
(42));
// Returns a Promise const
const value: number
value
= await
import Result
Result
.
const unwrap: <Result.ResultAsync<number, never>>(result: Result.ResultAsync<number, never>) => Promise<number> (+3 overloads)
unwrap
(
const asyncResult: Result.ResultAsync<number, never>
asyncResult
);
// value: 42

With default:

import { 
import Result
Result
} from '@praha/byethrow';
const
const asyncResult: Result.ResultAsync<never, string>
asyncResult
=
import Result
Result
.
const fail: <Promise<string>>(error: Promise<string>) => Result.ResultAsync<never, string> (+1 overload)
fail
(
var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.
PromiseConstructor.resolve<string>(value: string): Promise<string> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.@returnsA promise whose internal state matches the provided promise.
resolve
('error'));
const
const value: 0
value
= await
import Result
Result
.
const unwrap: <Result.ResultAsync<never, string>, 0>(result: Result.ResultAsync<never, string>, defaultValue: 0) => Promise<0> (+3 overloads)
unwrap
(
const asyncResult: Result.ResultAsync<never, string>
asyncResult
, 0);
// value: 0

When to Use unwrap

Good Use Cases

Use unwrap at the boundaries of your application—such as HTTP handlers, CLI entry points-where you need to exit the Result world and return plain values to the outside world.

import { 
import Result
Result
} from '@praha/byethrow';
const
const handleRequest: (req: Request) => Promise<Response>
handleRequest
= async (
req: Request
req
: Request):
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<Response> => {
return await
import Result
Result
.
const pipe: <Result.ResultAsync<number, "NotFound" | "Unexpected">, Result.ResultAsync<Response, "NotFound" | "Unexpected">, Result.ResultAsync<Response, "Unexpected">, Promise<Response>>(a: Result.ResultAsync<number, "NotFound" | "Unexpected">, ab: (a: Result.ResultAsync<number, "NotFound" | "Unexpected">) => Result.ResultAsync<Response, "NotFound" | "Unexpected">, bc: (b: Result.ResultAsync<Response, "NotFound" | "Unexpected">) => Result.ResultAsync<...>, cd: (c: Result.ResultAsync<...>) => Promise<...>) => Promise<...> (+25 overloads)
pipe
(
const processRequest: (req: Request) => Result.ResultAsync<number, "NotFound" | "Unexpected">
processRequest
(
req: Request
req
),
import Result
Result
.
const map: <Result.ResultAsync<number, "NotFound" | "Unexpected">, Response>(fn: (a: number) => Response) => (result: Result.ResultAsync<number, "NotFound" | "Unexpected">) => Result.ResultAsync<Response, "NotFound" | "Unexpected"> (+1 overload)
map
((
result: number
result
) => {
return new
var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response

The Response interface of the Fetch API represents the response to a request.

MDN Reference

Response
(
var JSON: JSON

An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.

JSON
.
JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)

Converts a JavaScript value to a JavaScript Object Notation (JSON) string.

@paramvalue A JavaScript value, usually an object or array, to be converted.@paramreplacer A function that transforms the results.@paramspace Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.@throws{TypeError} If a circular reference or a BigInt value is found.
stringify
(
result: number
result
), {
ResponseInit.status?: number | undefined
status
: 200 });
}),
import Result
Result
.
const orElse: <Result.ResultAsync<Response, "NotFound" | "Unexpected">, Result.Success<Response> | Result.Failure<"Unexpected">>(fn: (a: "NotFound" | "Unexpected") => Result.Success<Response> | Result.Failure<"Unexpected">) => (result: Result.ResultAsync<Response, "NotFound" | "Unexpected">) => Result.ResultAsync<Response, "Unexpected"> (+1 overload)
orElse
((
error: "NotFound" | "Unexpected"
error
) => {
switch (
error: "NotFound" | "Unexpected"
error
) {
case 'NotFound': return
import Result
Result
.
const succeed: <Response>(value: Response) => Result.Result<Response, never> (+1 overload)
succeed
(new
var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response

The Response interface of the Fetch API represents the response to a request.

MDN Reference

Response
('Not Found', {
ResponseInit.status?: number | undefined
status
: 404 }));
default: return
import Result
Result
.
const fail: <"Unexpected">(error: "Unexpected") => Result.Result<never, "Unexpected"> (+1 overload)
fail
(
error: "Unexpected"
error
);
} }), // Unexpected errors are thrown here and can be detected // by infrastructure-level error monitoring tools like Sentry or CloudWatch.
import Result
Result
.
const unwrap: <Result.ResultAsync<Response, "Unexpected">>() => (result: Result.ResultAsync<Response, "Unexpected">) => Promise<Response> (+3 overloads)
unwrap
(),
); };

Avoid Using unwrap

Avoid calling unwrap in the middle of your logic. Doing so exits the Result "world" prematurely, losing the benefits of type-safe error handling. Instead, keep values wrapped in Results and use combinators like map, flatMap, or orElse to transform them.

import { 
import Result
Result
} from '@praha/byethrow';
// ❌ Don't do this const
const bad: number
bad
=
import Result
Result
.
const unwrap: <Result.Result<42, never>>(result: Result.Result<42, never>) => 42 (+3 overloads)
unwrap
(
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42)) * 2;
// ✅ Do this instead const
const good: Result.Result<number, never>
good
=
import Result
Result
.
const pipe: <Result.Result<42, never>, Result.Result<number, never>>(a: Result.Result<42, never>, ab: (a: Result.Result<42, never>) => Result.Result<number, never>) => Result.Result<number, never> (+25 overloads)
pipe
(
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42),
import Result
Result
.
const map: <Result.Result<42, never>, number>(fn: (a: 42) => number) => (result: Result.Result<42, never>) => Result.Result<number, never> (+1 overload)
map
((
x: 42
x
) =>
x: 42
x
* 2),
);

References

FunctionPurpose
unwrap(result)Extracts the success value from a Result, or throws/returns default on failure
unwrapError(result)Extracts the error value from a Result, or throws/returns default on success