#Wrapping Functions
Sometimes you need to work with code that throws exceptions—third-party libraries, built-in APIs, or legacy code. The fn and try functions wrap these potentially throwing operations and convert them into Result types.
#Creating Reusable Wrappers with fn
The fn function wraps a potentially throwing function and returns a new function that returns a Result. This is useful when you want to create reusable wrappers:
import { import Result Result } from '@praha/byethrow';
const const parseJSON: (input: string) => Result.Result<unknown, Error> parseJSON = import Result Result .fn<(input: string) => unknown, Error>(options: {
try: (input: string) => unknown;
catch: (error: unknown) => Error;
}): (input: string) => Result.Result<unknown, Error> (+3 overloads)
export fn
Wraps a function that may throw and returns a new function that returns a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA new function that returns a Result or ResultAsync wrapping the original function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: (x: number) => {
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = fn(5); // Result.Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: (x: number) => x + 1,
});
const result = fn(1); // Result.Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: async (id: string) => await fetch(`/api/data/${id}`),
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = await fn('abc'); // Result.ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: async () => await Promise.resolve('ok'),
});
const result = await fn(); // Result.ResultAsync<string, never>
@categoryCreators fn ({
try: (input: string) => unknown try : (input: string input : string) => var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON .JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): anyConverts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.@throws{SyntaxError} If text is not valid JSON. parse (input: string input ) as unknown,
catch: (error: unknown) => Error catch : (error: unknown error ) => new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error ('Invalid JSON', { ErrorOptions.cause?: unknown cause : error: unknown error }),
});
const const result: Result.Result<unknown, Error> result = const parseJSON: (input: string) => Result.Result<unknown, Error> parseJSON ('{"name": "Alice"}');
// Type: Result.Result<unknown, Error>
if (import Result Result .const isSuccess: <Result.Result<unknown, Error>>(result: Result.Result<unknown, Error>) => result is Result.Success<unknown>Type guard to check if a
Result
is a
Success
.
@function@typeParamR - The type of the result to check.@paramresult - The Result to check.@returnstrue if the result is a Success , otherwise false.@exampleimport { Result } from '@praha/byethrow';
const result: Result.Result<number, string> = { type: 'Success', value: 10 };
if (Result.isSuccess(result)) {
console.log(result.value); // Safe access to value
}
@categoryType Guards isSuccess (const result: Result.Result<unknown, Error> result )) {
var console: Console console .Console.log(...data: any[]): voidThe console.log() static method outputs a message to the console.
log (const result: Result.Success<unknown> result .value: unknown value ); // { name: "Alice" }
}#How It Works
- The
tryproperty contains the function that might throw (can accept arguments) - The
catchproperty handles any thrown errors and converts them to your error type - Returns a wrapped function that returns a
Resultinstead of throwing
#Non-Throwing Functions
When you're certain a function won't throw, use the safe option:
import { import Result Result } from '@praha/byethrow';
const const double: (x: number) => Result.Result<number, never> double = import Result Result .fn<(x: number) => number>(options: {
safe: true;
try: (x: number) => number;
}): (x: number) => Result.Result<number, never> (+3 overloads)
export fn
Wraps a function that may throw and returns a new function that returns a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA new function that returns a Result or ResultAsync wrapping the original function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: (x: number) => {
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = fn(5); // Result.Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: (x: number) => x + 1,
});
const result = fn(1); // Result.Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: async (id: string) => await fetch(`/api/data/${id}`),
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = await fn('abc'); // Result.ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: async () => await Promise.resolve('ok'),
});
const result = await fn(); // Result.ResultAsync<string, never>
@categoryCreators fn ({
safe: true safe : true,
try: (x: number) => number try : (x: number x : number) => x: number x * 2,
});
const const result: Result.Result<number, never> result = const double: (x: number) => Result.Result<number, never> double (5);
// Type: Result.Result<number, never>
// The error type is `never` because we guarantee no exceptions#Working with Async Functions
The fn function seamlessly handles async functions, returning a function that produces ResultAsync:
import { import Result Result } from '@praha/byethrow';
const const fetchUser: (id: string) => Result.ResultAsync<{
id: string;
name: string;
}, Error>
fetchUser = import Result Result .fn<(id: string) => Promise<{
id: string;
name: string;
}>, Error>(options: {
try: (id: string) => Promise<{
id: string;
name: string;
}>;
catch: (error: unknown) => Error;
}): (id: string) => Result.ResultAsync<{
id: string;
name: string;
}, Error> (+3 overloads)
export fn
Wraps a function that may throw and returns a new function that returns a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA new function that returns a Result or ResultAsync wrapping the original function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: (x: number) => {
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = fn(5); // Result.Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: (x: number) => x + 1,
});
const result = fn(1); // Result.Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: async (id: string) => await fetch(`/api/data/${id}`),
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = await fn('abc'); // Result.ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: async () => await Promise.resolve('ok'),
});
const result = await fn(); // Result.ResultAsync<string, never>
@categoryCreators fn ({
try: (id: string) => Promise<{
id: string;
name: string;
}>
try : async (id: string id : string) => {
const const response: Response response = await function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> fetch (`/api/users/${id: string id }`);
if (!const response: Response response .Response.ok: booleanThe ok read-only property of the Response interface contains a Boolean stating whether the response was successful (status in the range 200-299) or not.
ok ) throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error ('Not found');
return await const response: Response response .Body.json(): Promise<any> json () as { id: string id : string; name: string name : string };
},
catch: (error: unknown) => Error catch : (error: unknown error ) => new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error ('Failed to fetch user', { ErrorOptions.cause?: unknown cause : error: unknown error }),
});
const const result: Result.Result<{
id: string;
name: string;
}, Error>
result = await const fetchUser: (id: string) => Result.ResultAsync<{
id: string;
name: string;
}, Error>
fetchUser ('123');
// Type: Result.Result<{ id: string; name: string }, Error>#Executing and Wrapping with try
The try function executes a function that might throw and returns a Result directly:
import { import Result Result } from '@praha/byethrow';
const const result: Result.Result<{
name: string;
}, Error>
result = import Result Result .try<() => {
name: string;
}, Error>(options: {
try: () => {
name: string;
};
catch: (error: unknown) => Error;
}): Result.Result<{
name: string;
}, Error> (+3 overloads)
export try
Executes a function that may throw and wraps the result in a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA Result or ResultAsync wrapping the function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => {
const x = Math.random() * 10 - 5;
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
// result is Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Math.random() + 1,
});
// result is Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => fetch('/api/data'),
catch: (error) => new Error('Fetch failed', { cause: error }),
});
// result is ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Promise.resolve('ok'),
});
// result is ResultAsync<string, never>
@categoryCreators try ({
try: () => {
name: string;
}
try : () => var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON .JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): anyConverts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.@throws{SyntaxError} If text is not valid JSON. parse ('{"name": "Alice"}') as { name: string name : string },
catch: (error: unknown) => Error catch : (error: unknown error ) => new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error ('Invalid JSON', { ErrorOptions.cause?: unknown cause : error: unknown error }),
});
// Type: Result.Result<{ name: string }, Error>
if (import Result Result .const isSuccess: <Result.Result<{
name: string;
}, Error>>(result: Result.Result<{
name: string;
}, Error>) => result is Result.Success<{
name: string;
}>
Type guard to check if a
Result
is a
Success
.
@function@typeParamR - The type of the result to check.@paramresult - The Result to check.@returnstrue if the result is a Success , otherwise false.@exampleimport { Result } from '@praha/byethrow';
const result: Result.Result<number, string> = { type: 'Success', value: 10 };
if (Result.isSuccess(result)) {
console.log(result.value); // Safe access to value
}
@categoryType Guards isSuccess (const result: Result.Result<{
name: string;
}, Error>
result )) {
var console: Console console .Console.log(...data: any[]): voidThe console.log() static method outputs a message to the console.
log (const result: Result.Success<{
name: string;
}>
result .value: {
name: string;
}
value .name: string name ); // "Alice"
}#How It Works
- The
tryproperty contains a zero-argument function that might throw - The
catchproperty handles any thrown errors and converts them to your error type - The function is executed immediately and returns a
Result
#Non-Throwing Functions
When you're certain a function won't throw, use the safe option to skip the catch handler:
import { import Result Result } from '@praha/byethrow';
const const result: Result.Result<number, never> result = import Result Result .try<() => number>(options: {
safe: true;
try: () => number;
}): Result.Result<number, never> (+3 overloads)
export try
Executes a function that may throw and wraps the result in a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA Result or ResultAsync wrapping the function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => {
const x = Math.random() * 10 - 5;
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
// result is Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Math.random() + 1,
});
// result is Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => fetch('/api/data'),
catch: (error) => new Error('Fetch failed', { cause: error }),
});
// result is ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Promise.resolve('ok'),
});
// result is ResultAsync<string, never>
@categoryCreators try ({
safe: true safe : true,
try: () => number try : () => var Math: MathAn intrinsic object that provides basic mathematics functionality and constants.
Math .Math.random(): numberReturns a pseudorandom number between 0 and 1.
random () + 1,
});
// Type: Result.Result<number, never>
// The error type is `never` because we guarantee no exceptions#Working with Async Functions
The try function seamlessly handles async functions, returning a ResultAsync:
import { import Result Result } from '@praha/byethrow';
const const result: Result.Result<Response, Error> result = await import Result Result .try<() => Promise<Response>, Error>(options: {
try: () => Promise<Response>;
catch: (error: unknown) => Error;
}): Result.ResultAsync<Response, Error> (+3 overloads)
export try
Executes a function that may throw and wraps the result in a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA Result or ResultAsync wrapping the function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => {
const x = Math.random() * 10 - 5;
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
// result is Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Math.random() + 1,
});
// result is Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => fetch('/api/data'),
catch: (error) => new Error('Fetch failed', { cause: error }),
});
// result is ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Promise.resolve('ok'),
});
// result is ResultAsync<string, never>
@categoryCreators try ({
try: () => Promise<Response> try : () => function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> fetch ('/api/health'),
catch: (error: unknown) => Error catch : (error: unknown error ) => new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error ('Health check failed', { ErrorOptions.cause?: unknown cause : error: unknown error }),
});
// Type: Result.Result<Response, Error>#Choosing Between fn and try
| Scenario | Function to Use |
|---|---|
| Execute once and get result immediately | try |
| Create a reusable wrapped function | fn |
| Function needs to accept arguments | fn |
| Inline one-off error handling | try |
#Example: When to Use Each
Use try for one-off executions:
import { import Result Result } from '@praha/byethrow';
// Reading config once at startup
const const config: Result.Result<Config, ConfigError> config = import Result Result .try<() => Config, ConfigError>(options: {
try: () => Config;
catch: (error: unknown) => ConfigError;
}): Result.Result<Config, ConfigError> (+3 overloads)
export try
Executes a function that may throw and wraps the result in a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA Result or ResultAsync wrapping the function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => {
const x = Math.random() * 10 - 5;
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
// result is Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Math.random() + 1,
});
// result is Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const result = Result.try({
try: () => fetch('/api/data'),
catch: (error) => new Error('Fetch failed', { cause: error }),
});
// result is ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const result = Result.try({
safe: true,
try: () => Promise.resolve('ok'),
});
// result is ResultAsync<string, never>
@categoryCreators try ({
try: () => Config try : () => var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON .JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): anyConverts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.@throws{SyntaxError} If text is not valid JSON. parse ('{"name": "Alice"}') as type Config = {
name: string;
}
Config ,
catch: (error: unknown) => ConfigError catch : (error: unknown error ) => new constructor ConfigError(message?: string, options?: ErrorOptions): ConfigError (+1 overload) ConfigError ('Invalid config', { ErrorOptions.cause?: unknown cause : error: unknown error }),
});Use fn for reusable utilities:
import { import Result Result } from '@praha/byethrow';
// Creating a reusable JSON parser
const const parseJSON: (input: string) => Result.Result<unknown, ParseError> parseJSON = import Result Result .fn<(input: string) => unknown, ParseError>(options: {
try: (input: string) => unknown;
catch: (error: unknown) => ParseError;
}): (input: string) => Result.Result<unknown, ParseError> (+3 overloads)
export fn
Wraps a function that may throw and returns a new function that returns a
Result
or
ResultAsync
.
You can use either a custom catch handler or rely on the safe: true option
to assume the function cannot throw.
@function@typeParamT - The function type to execute (sync or async) or a Promise type.@typeParamE - The error type to return if catch is used.@returnsA new function that returns a Result or ResultAsync wrapping the original function's return value or the caught error.@exampleSync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: (x: number) => {
if (x < 0) throw new Error('Negative!');
return x * 2;
},
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = fn(5); // Result.Result<number, Error>
@exampleSync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: (x: number) => x + 1,
});
const result = fn(1); // Result.Result<number, never>
@exampleAsync try-catch
import { Result } from '@praha/byethrow';
const fn = Result.fn({
try: async (id: string) => await fetch(`/api/data/${id}`),
catch: (error) => new Error('Oops!', { cause: error }),
});
const result = await fn('abc'); // Result.ResultAsync<Response, Error>
@exampleAsync safe
import { Result } from '@praha/byethrow';
const fn = Result.fn({
safe: true,
try: async () => await Promise.resolve('ok'),
});
const result = await fn(); // Result.ResultAsync<string, never>
@categoryCreators fn ({
try: (input: string) => unknown try : (input: string input : string) => var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON .JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): anyConverts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.@throws{SyntaxError} If text is not valid JSON. parse (input: string input ) as unknown,
catch: (error: unknown) => ParseError catch : (error: unknown error ) => new constructor ParseError(message?: string, options?: ErrorOptions): ParseError (+1 overload) ParseError ('Invalid JSON', { ErrorOptions.cause?: unknown cause : error: unknown error }),
});
// Use it multiple times
const const config: Result.Result<unknown, ParseError> config = const parseJSON: (input: string) => Result.Result<unknown, ParseError> parseJSON ('{"name": "Alice"}');
const const data: Result.Result<unknown, ParseError> data = const parseJSON: (input: string) => Result.Result<unknown, ParseError> parseJSON ('{"name": "Bob"}');#References
| Function | Purpose |
|---|---|
| try(options) | Execute a throwing function and return a Result |
| fn(options) | Wrap a throwing function into a Result-returning one |
