#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: PromiseConstructorRepresents 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: 42With 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: PromiseConstructorRepresents 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) => ResponseThe Response interface of the Fetch API represents the response to a request.
Response (var JSON: JSONAn 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) => ResponseThe Response interface of the Fetch API represents the response to a request.
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
| Function | Purpose |
|---|---|
| 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 |
