typescript-result
typescript-result copied to clipboard
Feature Request: Duality of `Result.all`
Why not add Result.any as the duality of Result.all, like Promise.all v.s. Promise.any and Array#every v.s. Array#some?
Interesting suggestion, let me break it down and get a feel for how this would look/behave:
declare a: Result<"a", ErrorA>;
declare b: Result<"b", ErrorB>;
declare c: Result<"c", ErrorC>;
-
Result.all- given one or multiple inputs, it returns aResultorAsyncResultwith a list of resolved encapsulated values on success, or the first error in case one of the inputs resolves to a failure.Result.all(a, b, c); // Result<["a", "b", "c"], ErrorA | ErrorB | ErrorC> -
Result.any- given one or multiple inputs, it returns aResultorAsyncResultwith the value of the first successful item it encounters, or a list of all errors in case all items turn out to be a failure. The inverse ofResult.all.Result.any(a, b, c); // Result<"a" | "b" | "c", [ErrorA, ErrorB, ErrorC]> -
Result.allSettled- given one or multiple inputs, it returns an array (or promise with an array if one of the provided items is async) of results that correspond to the provided input.Result.allSettled(a, b, c); // [Result<"a", ErrorA> , Result<"b", ErrorB>, Result<"c", ErrorC>]For sync input, this feels redundant tbh, but for async input it could make sense: execute multiple async operations in parallel, and do something with the settled outcome of all operations, whether that is success or failure. E.g.
declare function asyncOperationA(): AsyncResult<"a", ErrorA>; declare function asyncOperationB(): AsyncResult<"b", ErrorB>; declare function asyncOperationC(): AsyncResult<"c", ErrorC>; const results = await Result.allSettled( asyncOperationA(), asyncOperationB(), asyncOperationC() ); // [Result<"a", ErrorA>, Result<"b", ErrorB>, Result<"c", ErrorC>] for (const result of results) { if (!result.ok) { // Log, report, add to DLQ, etc... } } -
Result.race- also only makes sense for async operations -> given one or multiple inputs, it returns anAsyncResultwith the first item that settles (success or failure).Result.race(a, b, c); // AsyncResult<"a", ErrorA> | AsyncResult<"b", ErrorB> | AsyncResult<"c", ErrorC>
I feel like Result.any seems to be the most straightforward with regards to the expectations / compared to Promise.any.
With Result.allSettled and Result.race, I need to think about it some more, and some concrete use-cases would help as well to make sure that multiple angles and edge cases have been at least considered.
I guess it makes sense to start with Result.any and see where it goes from there. I'll let you know if I have any updates.