• English
  • Quick Start

    Get up and running with @praha/byethrow in minutes!

    This guide will walk you through the essential concepts and usage patterns.

    Installation

    Install the package using your preferred package manager:

    npm
    yarn
    pnpm
    bun
    deno
    npm install @praha/byethrow

    Basic Concepts

    @praha/byethrow provides a Result type that represents the outcome of an operation that might fail. Instead of throwing exceptions, functions return a Result that can be either:

    • Success: Contains a value of type T
    • Failure: Contains an error of type E

    This approach makes error handling explicit and predictable.

    Your First Result

    Let's start with a simple example:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    // Creating a successful result const
    const success: Result.Result<"Hello, World!", never>
    success
    =
    import Result
    Result
    .
    const succeed: <"Hello, World!">(value: "Hello, World!") => Result.Result<"Hello, World!", never> (+1 overload)
    succeed
    ('Hello, World!');
    // Creating a failed result const
    const failure: Result.Result<never, Error>
    failure
    =
    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'));
    // Checking the result if (
    import Result
    Result
    .
    const isSuccess: <Result.Result<"Hello, World!", never>>(result: Result.Result<"Hello, World!", never>) => result is Result.Success<"Hello, World!">

    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 success: Result.Result<"Hello, World!", never>
    success
    )) {
    var console: Console
    console
    .
    Console.log(...data: any[]): void

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

    MDN Reference

    log
    (
    const success: Result.Success<"Hello, World!">
    success
    .
    value: "Hello, World!"
    value
    ); // "Hello, World!"
    } if (
    import Result
    Result
    .
    const isFailure: <Result.Result<never, Error>>(result: Result.Result<never, Error>) => result is Result.Failure<Error>

    Type guard to check if a Result is a Failure .

    @function@typeParamR - The type of the result to check.@paramresult - The Result to check.@returnstrue if the result is a Failure , otherwise false.@example
    import { Result } from '@praha/byethrow';
    
    const result: Result.Result<number, string> = { type: 'Failure', error: 'Something went wrong' };
    if (Result.isFailure(result)) {
      console.error(result.error); // Safe access to error
    }
    @categoryType Guards
    isFailure
    (
    const failure: Result.Result<never, Error>
    failure
    )) {
    var console: Console
    console
    .
    Console.log(...data: any[]): void

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

    MDN Reference

    log
    (
    const failure: Result.Failure<Error>
    failure
    .
    error: Error
    error
    .
    Error.message: string
    message
    ); // "Something went wrong"
    }

    Handling Operations That Might Fail

    Use Result.fn to wrap functions that might throw exceptions:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const parseNumber: (input: string) => Result.Result<number, Error>
    parseNumber
    =
    import Result
    Result
    .
    fn<(input: string) => number, Error>(options: {
        try: (input: string) => number;
        catch: (error: unknown) => Error;
    }): (input: string) => Result.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) => {
    const
    const num: number
    num
    =
    var Number: NumberConstructor
    (value?: any) => number

    An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.

    Number
    (
    input: string
    input
    );
    if (
    var Number: NumberConstructor

    An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.

    Number
    .
    NumberConstructor.isNaN(number: unknown): boolean

    Returns a Boolean value that indicates whether a value is the reserved value NaN (not a number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter to a number. Only values of the type number, that are also NaN, result in true.

    @paramnumber A numeric value.
    isNaN
    (
    const num: number
    num
    )) {
    throw new
    var Error: ErrorConstructor
    new (message?: string, options?: ErrorOptions) => Error (+1 overload)
    Error
    ('Not a valid number');
    } return
    const num: number
    num
    ;
    },
    catch: (error: unknown) => Error
    catch
    : (
    error: unknown
    error
    ) => new
    var Error: ErrorConstructor
    new (message?: string, options?: ErrorOptions) => Error (+1 overload)
    Error
    ('Failed to parse number', {
    ErrorOptions.cause?: unknown
    cause
    :
    error: unknown
    error
    }),
    }); const
    const result: Result.Result<number, Error>
    result
    =
    const parseNumber: (input: string) => Result.Result<number, Error>
    parseNumber
    ('42');
    if (
    import Result
    Result
    .
    const isSuccess: <Result.Result<number, Error>>(result: Result.Result<number, Error>) => result is Result.Success<number>

    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<number, 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<number>
    result
    .
    value: number
    value
    ); // 42
    }

    Transforming Values

    Use Result.map to transform successful values:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const double: (x: number) => number
    double
    = (
    x: number
    x
    : number) =>
    x: number
    x
    * 2;
    const
    const result: Result.Result<number, never>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<21, never>, Result.Result<number, never>>(a: Result.Result<21, never>, ab: (a: Result.Result<21, never>) => Result.Result<number, never>) => Result.Result<number, never> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <21>(value: 21) => Result.Result<21, never> (+1 overload)
    succeed
    (21),
    import Result
    Result
    .
    const map: <Result.Result<21, never>, number>(fn: (a: 21) => number) => (result: Result.Result<21, never>) => Result.Result<number, never> (+1 overload)
    map
    (
    const double: (x: number) => number
    double
    )
    ); if (
    import Result
    Result
    .
    const isSuccess: <Result.Result<number, never>>(result: Result.Result<number, never>) => result is Result.Success<number>

    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<number, never>
    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<number>
    result
    .
    value: number
    value
    ); // 42
    }

    Chaining Operations

    One of the most powerful features is chaining operations together using Result.pipe:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const validateId: (id: string) => Result.Failure<Error> | Result.Success<string>
    validateId
    = (
    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 findUser: (id: string) => Result.Failure<Error> | Result.Success<{
        readonly id: "u123";
        readonly name: "John Doe";
    }>
    findUser
    = (
    id: string
    id
    : string) => {
    // Simulate a database lookup if (
    id: string
    id
    === 'u123') {
    return
    import Result
    Result
    .
    const succeed: <{
        readonly id: "u123";
        readonly name: "John Doe";
    }>(value: {
        readonly id: "u123";
        readonly name: "John Doe";
    }) => Result.Result<{
        readonly id: "u123";
        readonly name: "John Doe";
    }, never> (+1 overload)
    succeed
    ({
    id: "u123"
    id
    ,
    name: "John Doe"
    name
    : 'John Doe' });
    } 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
    ('User not found'));
    }; const
    const toWelcome: (user: Result.InferSuccess<typeof findUser>) => string
    toWelcome
    = (
    user: {
        readonly id: "u123";
        readonly name: "John Doe";
    }
    user
    :
    import Result
    Result
    .
    type InferSuccess<T> = [T] extends [(...args: any[]) => Result.ResultMaybeAsync<infer U, any>] ? U : [T] extends [Result.ResultMaybeAsync<infer U, any>] ? U : never

    Infers the Success value type T from a Result or a function returning a Result.

    @typeParamT - A ResultMaybeAsync type or a function returning it.@example

    From a result object

    import { Result } from '@praha/byethrow';
    
    type R = Result.Result<number, string>;
    type SuccessValue = Result.InferSuccess<R>; // number
    @example

    From a function

    import { Result } from '@praha/byethrow';
    
    const fn = () => Promise.resolve({ type: 'Success', value: 123 } as const);
    type SuccessValue = Result.InferSuccess<typeof fn>; // number
    @categoryInfer Types
    InferSuccess
    <typeof
    const findUser: (id: string) => Result.Failure<Error> | Result.Success<{
        readonly id: "u123";
        readonly name: "John Doe";
    }>
    findUser
    >) => {
    return `Welcome, ${
    user: {
        readonly id: "u123";
        readonly name: "John Doe";
    }
    user
    .
    name: "John Doe"
    name
    }!`;
    }; // Chain multiple operations const
    const result: Result.Result<string, Error>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<"u123", never>, Result.Result<string, Error>, Result.Result<{
        readonly id: "u123";
        readonly name: "John Doe";
    }, Error>, Result.Result<string, 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: "u123";
        readonly name: "John Doe";
    }, Error>, cd: (c: Result.Result<{
        readonly id: "u123";
        readonly name: "John Doe";
    }, Error>) => Result.Result<...>) => Result.Result<...> (+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 validateId: (id: string) => Result.Failure<Error> | Result.Success<string>
    validateId
    ),
    import Result
    Result
    .
    const andThen: <Result.Result<string, Error>, Result.Failure<Error> | Result.Success<{
        readonly id: "u123";
        readonly name: "John Doe";
    }>>(fn: (a: string) => Result.Failure<Error> | Result.Success<{
        readonly id: "u123";
        readonly name: "John Doe";
    }>) => (result: Result.Result<string, Error>) => Result.Result<{
        readonly id: "u123";
        readonly name: "John Doe";
    }, Error> (+1 overload)
    andThen
    (
    const findUser: (id: string) => Result.Failure<Error> | Result.Success<{
        readonly id: "u123";
        readonly name: "John Doe";
    }>
    findUser
    ),
    import Result
    Result
    .
    const map: <Result.Result<{
        readonly id: "u123";
        readonly name: "John Doe";
    }, Error>, string>(fn: (a: {
        readonly id: "u123";
        readonly name: "John Doe";
    }) => string) => (result: Result.Result<{
        readonly id: "u123";
        readonly name: "John Doe";
    }, Error>) => Result.Result<string, Error> (+1 overload)
    map
    (
    const toWelcome: (user: Result.InferSuccess<typeof findUser>) => string
    toWelcome
    )
    ); if (
    import Result
    Result
    .
    const isSuccess: <Result.Result<string, Error>>(result: Result.Result<string, Error>) => result is Result.Success<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.@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<string, 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<string>
    result
    .
    value: string
    value
    ); // "Welcome, John Doe!"
    }

    Error Handling

    Handle errors gracefully with Result.orElse:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const riskyOperation: () => Result.Result<never, Error>
    riskyOperation
    = () =>
    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
    ('Operation failed'));
    const
    const fallback: () => Result.Result<"Default value", never>
    fallback
    = () =>
    import Result
    Result
    .
    const succeed: <"Default value">(value: "Default value") => Result.Result<"Default value", never> (+1 overload)
    succeed
    ('Default value');
    const
    const result: Result.Result<"Default value", never>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<never, Error>, Result.Result<"Default value", never>>(a: Result.Result<never, Error>, ab: (a: Result.Result<never, Error>) => Result.Result<"Default value", never>) => Result.Result<"Default value", never> (+25 overloads)
    pipe
    (
    const riskyOperation: () => Result.Result<never, Error>
    riskyOperation
    (),
    import Result
    Result
    .
    const orElse: <Result.Result<never, Error>, Result.Result<"Default value", never>>(fn: (a: Error) => Result.Result<"Default value", never>) => (result: Result.Result<never, Error>) => Result.Result<"Default value", never> (+1 overload)
    orElse
    (
    const fallback: () => Result.Result<"Default value", never>
    fallback
    )
    ); if (
    import Result
    Result
    .
    const isSuccess: <Result.Result<"Default value", never>>(result: Result.Result<"Default value", never>) => result is Result.Success<"Default value">

    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<"Default value", never>
    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<"Default value">
    result
    .
    value: "Default value"
    value
    ); // "Default value"
    }

    Working with Async Operations

    @praha/byethrow works seamlessly with asynchronous operations:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const validateId: (id: string) => Result.Failure<Error> | Result.Success<string>
    validateId
    = (
    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 findUser: (userId: string) => Result.ResultAsync<any, Error>
    findUser
    =
    import Result
    Result
    .
    fn<(userId: string) => Promise<any>, Error>(options: {
        try: (userId: string) => Promise<any>;
        catch: (error: unknown) => Error;
    }): (userId: string) => Result.ResultAsync<any, 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: (userId: string) => Promise<any>
    try
    : async (
    userId: string
    userId
    : string) => {
    const
    const response: Response
    response
    = await
    function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
    fetch
    (`/api/users/${
    userId: string
    userId
    }`);
    return await
    const response: Response
    response
    .
    Body.json(): Promise<any>
    json
    ();
    },
    catch: (error: unknown) => Error
    catch
    : (
    error: unknown
    error
    ) => new
    var Error: ErrorConstructor
    new (message?: string, options?: ErrorOptions) => Error (+1 overload)
    Error
    ('Failed to find user', {
    ErrorOptions.cause?: unknown
    cause
    :
    error: unknown
    error
    }),
    }); const
    const result: Result.Result<any, Error>
    result
    = await
    import Result
    Result
    .
    const pipe: <Result.Result<"u123", never>, Result.Result<string, Error>, Result.ResultAsync<any, Error>>(a: Result.Result<"u123", never>, ab: (a: Result.Result<"u123", never>) => Result.Result<string, Error>, bc: (b: Result.Result<string, Error>) => Result.ResultAsync<any, Error>) => Result.ResultAsync<any, 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 validateId: (id: string) => Result.Failure<Error> | Result.Success<string>
    validateId
    ),
    import Result
    Result
    .
    const andThen: <Result.Result<string, Error>, Result.ResultAsync<any, Error>>(fn: (a: string) => Result.ResultAsync<any, Error>) => (result: Result.Result<string, Error>) => Result.ResultAsync<any, Error> (+1 overload)
    andThen
    (
    const findUser: (userId: string) => Result.ResultAsync<any, Error>
    findUser
    ),
    ); if (
    import Result
    Result
    .
    const isSuccess: <Result.Result<any, Error>>(result: Result.Result<any, Error>) => result is Result.Success<any>

    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<any, 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
    ('User data:',
    const result: Result.Success<any>
    result
    .
    value: any
    value
    );
    }

    Happy coding with @praha/byethrow! 🚀