@@ -61,6 +61,31 @@ export namespace Result {
6161
6262export type Result < T , E > = Ok < T , E > | Err < T , E >
6363
64+ type TaggedErrorUnion = TaggedError < string >
65+ type CatchTagsHandlers = {
66+ [ K in string ] ?: ( error : TaggedErrorUnion ) => Result < unknown , unknown >
67+ }
68+ type CatchTagsHandlersFor < E > = Partial <
69+ {
70+ [ K in Extract < Extract < E , TaggedErrorUnion > [ '_tag' ] , string > ] : (
71+ error : Extract < Extract < E , TaggedErrorUnion > , { _tag : K } > ,
72+ ) => Result < unknown , unknown >
73+ }
74+ >
75+ type CatchTagsHandlerResultUnion < Handlers > = {
76+ [ K in keyof Handlers ] : Handlers [ K ] extends ( ...args : readonly unknown [ ] ) => infer R ? R : never
77+ } [ keyof Handlers ]
78+
79+ export class TaggedError < Tag extends string = string > extends Error {
80+ readonly _tag : Tag
81+
82+ constructor ( tag : Tag , message ?: string ) {
83+ super ( message )
84+ this . _tag = tag
85+ this . name = this . constructor . name
86+ }
87+ }
88+
6489export function ok < T , E = never > ( value : T ) : Ok < T , E >
6590export function ok < T extends void = void , E = never > ( value : void ) : Ok < void , E >
6691export function ok < T , E = never > ( value : T ) : Ok < T , E > {
@@ -232,6 +257,16 @@ interface IResult<T, E> {
232257 ) : Result < InferOkTypes < R > | T , InferErrTypes < R > >
233258 orElse < U , A > ( f : ( e : E ) => Result < U , A > ) : Result < U | T , A >
234259
260+ /**
261+ * Catches tagged errors by matching against the `_tag` property.
262+ */
263+ catchTags < Handlers extends CatchTagsHandlersFor < E > > (
264+ handlers : Handlers ,
265+ ) : Result <
266+ T | InferOkTypes < CatchTagsHandlerResultUnion < Handlers > > ,
267+ E | InferErrTypes < CatchTagsHandlerResultUnion < Handlers > >
268+ >
269+
235270 /**
236271 * Similar to `map` Except you must return a new `Result`.
237272 *
@@ -367,6 +402,15 @@ export class Ok<T, E> implements IResult<T, E> {
367402 return ok ( this . value )
368403 }
369404
405+ catchTags < Handlers extends CatchTagsHandlersFor < E > > (
406+ _handlers : Handlers ,
407+ ) : Result <
408+ T | InferOkTypes < CatchTagsHandlerResultUnion < Handlers > > ,
409+ E | InferErrTypes < CatchTagsHandlerResultUnion < Handlers > >
410+ > {
411+ return ok ( this . value )
412+ }
413+
370414 asyncAndThen < U , F > ( f : ( t : T ) => ResultAsync < U , F > ) : ResultAsync < U , E | F > {
371415 return f ( this . value )
372416 }
@@ -396,8 +440,10 @@ export class Ok<T, E> implements IResult<T, E> {
396440
397441 safeUnwrap ( ) : Generator < Err < never , E > , T > {
398442 const value = this . value
399- /* eslint-disable-next-line require-yield */
400443 return ( function * ( ) {
444+ for ( const _err of [ ] as Err < never , E > [ ] ) {
445+ yield _err
446+ }
401447 return value
402448 } ) ( )
403449 }
@@ -410,8 +456,10 @@ export class Ok<T, E> implements IResult<T, E> {
410456 throw createNeverThrowError ( 'Called `_unsafeUnwrapErr` on an Ok' , this , config )
411457 }
412458
413- // eslint-disable-next-line @typescript-eslint/no-this-alias, require-yield
414459 * [ Symbol . iterator ] ( ) : Generator < Err < never , E > , T > {
460+ for ( const _err of [ ] as Err < never , E > [ ] ) {
461+ yield _err
462+ }
415463 return this . value
416464 }
417465}
@@ -471,6 +519,31 @@ export class Err<T, E> implements IResult<T, E> {
471519 return f ( this . error )
472520 }
473521
522+ catchTags < Handlers extends CatchTagsHandlersFor < E > > (
523+ handlers : Handlers ,
524+ ) : Result <
525+ T | InferOkTypes < CatchTagsHandlerResultUnion < Handlers > > ,
526+ E | InferErrTypes < CatchTagsHandlerResultUnion < Handlers > >
527+ > {
528+ if ( this . error instanceof TaggedError ) {
529+ const keyedHandlers = handlers as CatchTagsHandlers
530+ const handler = keyedHandlers [ this . error . _tag ] as
531+ | ( ( error : TaggedErrorUnion ) => Result < unknown , unknown > )
532+ | undefined
533+ if ( handler !== undefined ) {
534+ return handler ( this . error as TaggedErrorUnion ) as Result <
535+ T | InferOkTypes < CatchTagsHandlerResultUnion < Handlers > > ,
536+ E | InferErrTypes < CatchTagsHandlerResultUnion < Handlers > >
537+ >
538+ }
539+ }
540+
541+ return err ( this . error ) as Result <
542+ T | InferOkTypes < CatchTagsHandlerResultUnion < Handlers > > ,
543+ E | InferErrTypes < CatchTagsHandlerResultUnion < Handlers > >
544+ >
545+ }
546+
474547 // eslint-disable-next-line @typescript-eslint/no-unused-vars
475548 asyncAndThen < U , F > ( _f : ( t : T ) => ResultAsync < U , F > ) : ResultAsync < U , E | F > {
476549 return errAsync < U , E > ( this . error )
0 commit comments