logo
byethrow
Guide
Examples
API Reference
Guide
Examples
API Reference
logo
byethrow

Getting Started

Introduction
Why byethrow?
Quick Start
Importing Result

Best Practices

Result vs throw
Custom Error
Pattern Matching

Tools & Integrations

MCP Server
ESLint Plugin

Last Updated: 2025/10/13 08:39:30

Previous PageQuick Start
Next PageResult vs throw

#Importing Result

@praha/byethrow provides two distinct import methods to balance efficient development with optimal bundle size. Both approaches fully support tree-shaking, ensuring that unused features are automatically excluded from your final bundle.

#Two Import Methods

#Explicit Namespace Approach (Result)

For verbose and explicit code that prioritizes clarity, use the Result namespace:

import { 
import Result
Result
} from '@praha/byethrow';
const
const validateUser: (id: string) => Result.Failure<Error> | Result.Success<string>
validateUser
= (
id: string
id
: string) => {
if (!
id: string
id
.
String.startsWith(searchString: string, position?: number): boolean

Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.

startsWith
('u')) {
return
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
('Invalid ID format'));
} return
import Result
Result
.
const succeed: <string>(value: string) => Result.Result<string, never> (+1 overload)
succeed
(
id: string
id
);
}; const
const result: Result.Result<{
    id: string;
    name: string;
}, Error>
result
=
import Result
Result
.
const pipe: <Result.Result<string, never>, Result.Result<string, Error>, Result.Result<{
    id: string;
    name: string;
}, Error>>(a: Result.Result<string, never>, ab: (a: Result.Result<string, never>) => Result.Result<string, Error>, bc: (b: Result.Result<string, Error>) => Result.Result<{
    id: string;
    name: string;
}, Error>) => Result.Result<{
    id: string;
    name: string;
}, Error> (+25 overloads)
pipe
(
import Result
Result
.
const succeed: <string>(value: string) => Result.Result<string, never> (+1 overload)
succeed
('u123'),
import Result
Result
.
const andThen: <Result.Result<string, never>, Result.Failure<Error> | Result.Success<string>>(fn: (a: string) => Result.Failure<Error> | Result.Success<string>) => (result: Result.Result<string, never>) => Result.Result<string, Error> (+1 overload)
andThen
(
const validateUser: (id: string) => Result.Failure<Error> | Result.Success<string>
validateUser
),
import Result
Result
.
const map: <Result.Result<string, Error>, {
    id: string;
    name: string;
}>(fn: (a: string) => {
    id: string;
    name: string;
}) => (result: Result.Result<string, Error>) => Result.Result<{
    id: string;
    name: string;
}, Error> (+1 overload)
map
(
id: string
id
=> ({
id: string
id
,
name: string
name
: 'John Doe' }))
); if (
import Result
Result
.
const isSuccess: <{
    id: string;
    name: string;
}>(result: Result.Result<{
    id: string;
    name: string;
}, unknown>) => result is Result.Success<{
    id: string;
    name: string;
}>

Type guard to check if a Result is a Success .

@function@typeParamT - The type of the success value.@paramresult - The Result to check.@returnstrue if the result is a Success, otherwise false.@example
import { 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<{
    id: string;
    name: string;
}, Error>
result
)) {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
@seesource
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0 .1.100
log
(
const result: Result.Success<{
    id: string;
    name: string;
}>
result
.
value: {
    id: string;
    name: string;
}
value
);
}

#Shorthand Alias (R)

For concise code that favors brevity, use the R alias:

import { 
import R
R
} from '@praha/byethrow';
const
const validateUser: (id: string) => R.Failure<Error> | R.Success<string>
validateUser
= (
id: string
id
: string) => {
if (!
id: string
id
.
String.startsWith(searchString: string, position?: number): boolean

Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.

startsWith
('u')) {
return
import R
R
.
const fail: <Error>(error: Error) => R.Result<never, Error> (+1 overload)
fail
(new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('Invalid ID format'));
} return
import R
R
.
const succeed: <string>(value: string) => R.Result<string, never> (+1 overload)
succeed
(
id: string
id
);
}; const
const result: R.Result<{
    id: string;
    name: string;
}, Error>
result
=
import R
R
.
const pipe: <R.Result<string, never>, R.Result<string, Error>, R.Result<{
    id: string;
    name: string;
}, Error>>(a: R.Result<string, never>, ab: (a: R.Result<string, never>) => R.Result<string, Error>, bc: (b: R.Result<string, Error>) => R.Result<{
    id: string;
    name: string;
}, Error>) => R.Result<{
    id: string;
    name: string;
}, Error> (+25 overloads)
pipe
(
import R
R
.
const succeed: <string>(value: string) => R.Result<string, never> (+1 overload)
succeed
('u123'),
import R
R
.
const andThen: <R.Result<string, never>, R.Failure<Error> | R.Success<string>>(fn: (a: string) => R.Failure<Error> | R.Success<string>) => (result: R.Result<string, never>) => R.Result<string, Error> (+1 overload)
andThen
(
const validateUser: (id: string) => R.Failure<Error> | R.Success<string>
validateUser
),
import R
R
.
const map: <R.Result<string, Error>, {
    id: string;
    name: string;
}>(fn: (a: string) => {
    id: string;
    name: string;
}) => (result: R.Result<string, Error>) => R.Result<{
    id: string;
    name: string;
}, Error> (+1 overload)
map
(
id: string
id
=> ({
id: string
id
,
name: string
name
: 'John Doe' }))
); if (
import R
R
.
const isSuccess: <{
    id: string;
    name: string;
}>(result: R.Result<{
    id: string;
    name: string;
}, unknown>) => result is R.Success<{
    id: string;
    name: string;
}>

Type guard to check if a Result is a Success .

@function@typeParamT - The type of the success value.@paramresult - The Result to check.@returnstrue if the result is a Success, otherwise false.@example
import { 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: R.Result<{
    id: string;
    name: string;
}, Error>
result
)) {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
@seesource
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0 .1.100
log
(
const result: R.Success<{
    id: string;
    name: string;
}>
result
.
value: {
    id: string;
    name: string;
}
value
);
}

#Tree-Shaking Support

@praha/byethrow achieves complete tree-shaking support:

// Example: Usage in a small application
import { 
import R
R
} from '@praha/byethrow';
// Only these features are actually used const
const parseNumber: (input: string) => R.Result<number, Error>
parseNumber
=
import R
R
.
try<(input: string) => number, Error>(options: {
    try: (input: string) => number;
    catch: (error: unknown) => Error;
}): (input: string) => R.Result<number, Error> (+7 overloads)
export try

Wraps a function execution (sync or async) or a Promise in a Result or ResultAsync type, capturing errors and returning them in a structured way.

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.@example

Sync try-catch

import { Result } from '@praha/byethrow';

const fn = Result.try({
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>
@example

Sync try-catch with immediate execution

import { Result } from '@praha/byethrow';

const result = Result.try({
immediate: true,
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>
@example

Sync safe

import { Result } from '@praha/byethrow';

const fn = Result.try({
safe: true,
try: (x: number) => x + 1,
});

const result = fn(1); // Result.Result<number, never>
@example

Sync safe with immediate execution

import { Result } from '@praha/byethrow';

const result = Result.try({
safe: true,
immediate: true,
try: () => Math.random() + 1,
});

// result is Result<number, never>
@example

Async try-catch

import { Result } from '@praha/byethrow';

const fn = Result.try({
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>
@example

Async try-catch with immediate execution

import { Result } from '@praha/byethrow';

const result = Result.try({
immediate: true,
try: () => fetch('/api/data'),
catch: (error) => new Error('Fetch failed', { cause: error }),
});

// result is ResultAsync<Response, Error>
@example

Async safe

import { Result } from '@praha/byethrow';

const fn = Result.try({
safe: true,
try: async () => await Promise.resolve('ok'),
});

const result = await fn(); // Result.ResultAsync<string, never>
@example

Async safe with immediate execution

import { Result } from '@praha/byethrow';

const result = Result.try({
safe: true,
immediate: true,
try: () => Promise.resolve('ok'),
});

// result is ResultAsync<string, never>
@categoryCreators
try
({
try: (input: string) => number
try
: (
input: string
input
: string) =>
function parseInt(string: string, radix?: number): number

Converts a string to an integer.

@paramstring A string to convert into a number.@paramradix A value between 2 and 36 that specifies the base of the number in string. If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal. All other strings are considered decimal.
parseInt
(
input: string
input
, 10),
catch: (error: unknown) => Error
catch
: () => new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('Invalid number')
}); // In this case, only the minimal code required for parseNumber // is included in the bundle, while other features (combine, pipe, etc.) are excluded

#Best Practices

#Choosing Between Import Methods

  • Use Result if you prefer explicit and descriptive naming that clearly indicates the purpose of each operation
  • Use R if you prefer fewer keystrokes and more concise code for faster development

#Important: Avoid Mixing Import Methods

We strongly recommend against mixing Result and R within the same codebase. Choose one approach and stick with it consistently throughout your project to maintain code readability and consistency.

// @filename: mixed-imports.ts
// ❌ Don't mix approaches - this creates inconsistent code
import { 
import Result
Result
,
import R
R
} from '@praha/byethrow';
const
const validateId: (id: string) => Result.Result<string, never>
validateId
= (
id: string
id
: string) => {
return
import Result
Result
.
const succeed: <string>(value: string) => Result.Result<string, never> (+1 overload)
succeed
(
id: string
id
); // Using Result
}; const
const processData: Result.Result<string, never>
processData
=
import R
R
.
const pipe: <Result.Result<string, never>, Result.Result<string, never>>(a: Result.Result<string, never>, ab: (a: Result.Result<string, never>) => Result.Result<string, never>) => Result.Result<string, never> (+25 overloads)
pipe
( // Using R
import R
R
.
const succeed: <string>(value: string) => Result.Result<string, never> (+1 overload)
succeed
('data'),
import R
R
.
const andThen: <Result.Result<string, never>, Result.Result<string, never>>(fn: (a: string) => Result.Result<string, never>) => (result: Result.Result<string, never>) => Result.Result<string, never> (+1 overload)
andThen
(
const validateId: (id: string) => Result.Result<string, never>
validateId
)
); // @filename: consistent-imports.ts // ✅ Choose one approach and use it consistently import {
import Result
Result
} from '@praha/byethrow';
const
const validateId: (id: string) => Result.Result<string, never>
validateId
= (
id: string
id
: string) => {
return
import Result
Result
.
const succeed: <string>(value: string) => Result.Result<string, never> (+1 overload)
succeed
(
id: string
id
);
}; const
const processData: Result.Result<string, never>
processData
=
import Result
Result
.
const pipe: <Result.Result<string, never>, Result.Result<string, never>>(a: Result.Result<string, never>, ab: (a: Result.Result<string, never>) => Result.Result<string, never>) => Result.Result<string, never> (+25 overloads)
pipe
(
import Result
Result
.
const succeed: <string>(value: string) => Result.Result<string, never> (+1 overload)
succeed
('data'),
import Result
Result
.
const andThen: <Result.Result<string, never>, Result.Result<string, never>>(fn: (a: string) => Result.Result<string, never>) => (result: Result.Result<string, never>) => Result.Result<string, never> (+1 overload)
andThen
(
const validateId: (id: string) => Result.Result<string, never>
validateId
)
);

Regardless of which method you choose, bundlers will automatically optimize your code, ensuring only the necessary features are included in your final bundle.