#no-try-catch-in-callback
Disallows try-catch blocks inside callbacks passed to @praha/byethrow functions such as Result.andThen, Result.map, etc.
#Rule details
A try-catch inside a @praha/byethrow callback is a sign that error handling has escaped the Result model. Use Result.fn() to wrap potentially-throwing code into a Result, keeping the pipeline clean.
#Incorrect
import { import Result Result } from '@praha/byethrow';
// ❌ try-catch inside a callback
const const result: Result.Result<any, ParseError> result = import Result Result .const pipe: <Result.Result<"{\"key\": \"value\"}", never>, Result.Result<any, ParseError>>(a: Result.Result<"{\"key\": \"value\"}", never>, ab: (a: Result.Result<"{\"key\": \"value\"}", never>) => Result.Result<any, ParseError>) => Result.Result<any, ParseError> (+25 overloads) pipe (
import Result Result .const succeed: <"{\"key\": \"value\"}">(value: "{\"key\": \"value\"}") => Result.Result<"{\"key\": \"value\"}", never> (+1 overload) succeed ('{"key": "value"}'),
import Result Result .const andThen: <Result.Result<"{\"key\": \"value\"}", never>, Result.Success<any> | Result.Failure<ParseError>>(fn: (a: "{\"key\": \"value\"}") => Result.Success<any> | Result.Failure<ParseError>) => (result: Result.Result<"{\"key\": \"value\"}", never>) => Result.Result<any, ParseError> (+1 overload) andThen ((value: "{\"key\": \"value\"}" value ) => {
try {
return import Result Result .const succeed: <any>(value: any) => Result.Result<any, never> (+1 overload) succeed (var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON .JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): anyConverts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.@throws{SyntaxError} If text is not valid JSON. parse (value: "{\"key\": \"value\"}" value ));
} catch {
return import Result Result .const fail: <ParseError>(error: ParseError) => Result.Result<never, ParseError> (+1 overload) fail (new constructor ParseError(message?: string, options?: ErrorOptions): ParseError (+1 overload) ParseError ());
}
}),
);#Correct
import { import Result Result } from '@praha/byethrow';
const const parser: (value: string) => Result.ResultAsync<any, ParseError> parser = import Result Result .fn<(value: string) => any, ParseError>(options: {
try: (value: string) => any;
catch: (error: unknown) => ParseError;
}): (value: string) => Result.ResultAsync<any, ParseError> (+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.@exampleSync 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>
@exampleSync 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>
@exampleAsync 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>
@exampleAsync 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: (value: string) => any try : (value: string value : string) => var JSON: JSONAn intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON .JSON.parse(text: string, reviver?: (this: any, key: string, value: any) => any): anyConverts a JavaScript Object Notation (JSON) string into an object.
@paramtext A valid JSON string.@paramreviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.@throws{SyntaxError} If text is not valid JSON. parse (value: string value ),
catch: (error: unknown) => ParseError catch : (error: unknown error : unknown) => new constructor ParseError(message?: string, options?: ErrorOptions): ParseError (+1 overload) ParseError (),
});
// ✅ wrapping with Result.fn()
const const result: Result.ResultAsync<any, ParseError> result = import Result Result .const pipe: <Result.Result<"{\"key\": \"value\"}", never>, Result.ResultAsync<any, ParseError>>(a: Result.Result<"{\"key\": \"value\"}", never>, ab: (a: Result.Result<"{\"key\": \"value\"}", never>) => Result.ResultAsync<any, ParseError>) => Result.ResultAsync<any, ParseError> (+25 overloads) pipe (
import Result Result .const succeed: <"{\"key\": \"value\"}">(value: "{\"key\": \"value\"}") => Result.Result<"{\"key\": \"value\"}", never> (+1 overload) succeed ('{"key": "value"}'),
import Result Result .const andThen: <Result.Result<"{\"key\": \"value\"}", never>, Result.ResultAsync<any, ParseError>>(fn: (a: "{\"key\": \"value\"}") => Result.ResultAsync<any, ParseError>) => (result: Result.Result<"{\"key\": \"value\"}", never>) => Result.ResultAsync<any, ParseError> (+1 overload) andThen (const parser: (value: string) => Result.ResultAsync<any, ParseError> parser ),
);