logo
byethrow
  • Guide
  • Examples
  • API Reference
    Getting Started
    Introduction
    Why byethrow?
    Quick Start
    Importing Result
    Best Practices
    Result vs throw
    Custom Error
    Pattern Matching
    Tools & Integrations
    MCP Server
    ESLint Plugin
    📝 Edit this page

    Last Updated: 11/28/2025, 5:42:58 AM

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

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

    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<{
        readonly id: string;
        readonly name: "John Doe";
    }, 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<{
        readonly id: string;
        readonly name: "John Doe";
    }>
    result
    .
    value: {
        readonly id: string;
        readonly name: "John Doe";
    }
    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<"data", never>, Result.Result<string, never>>(a: Result.Result<"data", never>, ab: (a: Result.Result<"data", never>) => Result.Result<string, never>) => Result.Result<string, never> (+25 overloads)
    pipe
    ( // Using R
    import R
    R
    .
    const succeed: <"data">(value: "data") => Result.Result<"data", never> (+1 overload)
    succeed
    ('data'),
    import R
    R
    .
    const andThen: <Result.Result<"data", never>, Result.Result<string, never>>(fn: (a: "data") => Result.Result<string, never>) => (result: Result.Result<"data", 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<"data", never>, Result.Result<string, never>>(a: Result.Result<"data", never>, ab: (a: Result.Result<"data", never>) => Result.Result<string, never>) => Result.Result<string, never> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <"data">(value: "data") => Result.Result<"data", never> (+1 overload)
    succeed
    ('data'),
    import Result
    Result
    .
    const andThen: <Result.Result<"data", never>, Result.Result<string, never>>(fn: (a: "data") => Result.Result<string, never>) => (result: Result.Result<"data", 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.