For AI agents: the complete documentation index is available at /byethrow/llms.txt, the full documentation bundle is available at /byethrow/llms-full.txt, and this page is available as Markdown at /byethrow/index.md.
  • English
  • byethrow

    A lightweight Result type package

    Say goodbye to throw, embrace type-safe results

    npm install @praha/byethrow
    any
    1const parseJson = (text: string) => {2  return JSON.parse(text); // may throw, but the type won't say3};4 5try {6  const data = parseJson('{ "answer": 21 }');7  console.log(data.answer * 2); // data: any8} catch (error) {9  // error: unknown. What could it be?10}
    Uncheckederrors never show up in the type
    Why byethrow

    Error handling that the compiler understands

    Every failure becomes a value. No hidden throws, no forgotten catches, no surprises in production.

    Result<T, E>Success { value: T }Failure { error: E }

    01Errors are values

    Functions return Result<T, E> instead of throwing. Success carries the value, Failure carries the error, and the type checker makes sure you handle both.

    Learn more
    { type: 'Success', value: 42 }
    { type: 'Failure', error: NotFound }
    JSON.stringify ✓structuredClone ✓no instanceof

    02Just plain objects

    No classes, no instanceof, no hidden state. Log it, serialize it, send it across the wire as it is.

    Learn more
    Result<T, E>ResultAsync<T, E>map(fn)UU

    03Sync and async, one API

    Every function accepts both Result and Promise<Result>. There is no second API to learn.

    Learn more
    succeed(id)andThen(findUser)map(toDto)unwrap()

    a failure skips every remaining step

    04Composable by design

    Chain steps with pipe. Each function only runs on success, and a failure flows straight through to the end.

    Learn more
    pipesucceedfailmapandThenorElsetryfncollectunwrapsequenceparse
    in your bundletree-shaken away

    05Ship only what you use

    Each function is an independent export, so bundlers drop everything you never call.

    Learn more
    Linter pluginno-throw-in-callback
    Test matchersexpect(result).toBeSuccess()
    Docs for AI assistantsbyethrow-docs init claude

    06Batteries included

    A linter plugin, test matchers and documentation for AI assistants keep the whole team on the same patterns.

    Learn more
    In practice

    Every failure path, visible in the types

    These snippets are type-checked on every docs build. Hover over any identifier to see what the compiler sees.

    Result.fn turns a throwing or async function into one that returns a Result.

    fetch-user.tsHover to inspect types
    import { 
    import Result
    Result
    } from '@praha/byethrow';
    type
    type User = {
        id: string;
        name: string;
    }
    User
    = {
    id: string
    id
    : string;
    name: string
    name
    : string };
    const
    const fetchUser: (id: string) => Result.ResultAsync<User, Error>
    fetchUser
    =
    import Result
    Result
    .
    fn<(id: string) => Promise<User>, Error>(options: {
        try: (id: string) => Promise<User>;
        catch: (error: unknown) => Error;
    }): (id: string) => Result.ResultAsync<User, 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: (id: string) => Promise<User>
    try
    : async (
    id: string
    id
    : string):
    interface Promise<T>

    Represents the completion of an asynchronous operation

    Promise
    <
    type User = {
        id: string;
        name: string;
    }
    User
    > => {
    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: boolean

    The 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.

    MDN Reference

    ok
    ) throw new
    var Error: ErrorConstructor
    new (message?: string, options?: ErrorOptions) => Error (+1 overload)
    Error
    (`HTTP ${
    const response: Response
    response
    .
    Response.status: number

    The status read-only property of the Response interface contains the HTTP status codes of the response.

    MDN Reference

    status
    }`);
    return
    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 fetch user', {
    ErrorOptions.cause?: unknown
    cause
    :
    error: unknown
    error
    }),
    }); const
    const result: Result.Result<User, Error>
    result
    = await
    const fetchUser: (id: string) => Result.ResultAsync<User, Error>
    fetchUser
    ('u_123');
    Get started

    Say goodbye to throw.

    Install the package and turn your first function into one that returns a Result. It takes about a minute.

    npm install @praha/byethrow