# Fx.catchTags

Recovers several tagged typed-error variants with one handler table.

## Signatures

```ts
export declare const catchTags: {
    <E, Cases extends TaggedCase<E>>(cases: Cases): <A, R>(self: Fx<A, E, R>) => Fx<A | {
        [K in keyof Cases]: CaseSuccess<Cases[K]>;
    }[keyof Cases], Exclude<E, {
        _tag: keyof Cases;
    }> | {
        [K in keyof Cases]: CaseError<Cases[K]>;
    }[keyof Cases], R | {
        [K in keyof Cases]: CaseServices<Cases[K]>;
    }[keyof Cases]>;
    <A, E, R, Cases extends TaggedCase<E>>(self: Fx<A, E, R>, cases: Cases): Fx<A | {
        [K in keyof Cases]: CaseSuccess<Cases[K]>;
    }[keyof Cases], Exclude<E, {
        _tag: keyof Cases;
    }> | {
        [K in keyof Cases]: CaseError<Cases[K]>;
    }[keyof Cases], R | {
        [K in keyof Cases]: CaseServices<Cases[K]>;
    }[keyof Cases]>;
};
```

## Why

A handler table keeps multi-variant recovery exhaustive and preserves the
precise success, error, and service unions produced by each selected case.
Unlisted variants remain visible in the returned error channel.

## Ownership and lifetime

The first Fail found anywhere in the source Cause is inspected. A listed tag
starts exactly one handler Fx and replaces the entire original Cause,
including any defects or interrupts composed with that Fail. An untagged or
unlisted first Fail, or a Cause with no Fail, propagates intact. Handlers are
lazy and contribute their individual errors and service requirements.

## Examples

```ts
import { catchTags } from "@typed/fx/Fx"
import { fail, succeed } from "@typed/fx/Fx"

type Failure =
  | { readonly _tag: "Missing"; readonly id: string }
  | { readonly _tag: "Forbidden" }
const source = fail<Failure>({ _tag: "Missing", id: "42" })
const recovered = catchTags(source, {
  Missing: ({ id }) => succeed(`missing:${id}`),
  Forbidden: () => succeed("forbidden")
})
```
