• English
  • Importing Result

    @praha/byethrow provides two distinct import methods to balance efficient development with learnability. 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: <Result.Result<{
        readonly id: string;
        readonly name: "John Doe";
    }, Error>>(result: Result.Result<{
        readonly id: string;
        readonly name: "John Doe";
    }, Error>) => result is Result.Success<{
        readonly id: string;
        readonly name: "John Doe";
    }>

    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.@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
    console
    .
    Console.log(...data: any[]): void

    The console.log() static method outputs a message to the console.

    MDN Reference

    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: <R.Result<{
        readonly id: string;
        readonly name: "John Doe";
    }, Error>>(result: R.Result<{
        readonly id: string;
        readonly name: "John Doe";
    }, Error>) => result is R.Success<{
        readonly id: string;
        readonly name: "John Doe";
    }>

    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.@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
    console
    .
    Console.log(...data: any[]): void

    The console.log() static method outputs a message to the console.

    MDN Reference

    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
    .
    fn<(input: string) => number, Error>(options: {
        try: (input: string) => number;
        catch: (error: unknown) => Error;
    }): (input: string) => R.Result<number, 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.@example

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

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

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

    Async 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) => 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 (andThen, 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
    )
    );