# zipLatestWith

Zips two Fx streams by latest values and combines each pair with a function.
Waits for both to emit at least once, then emits `f(left, right)` whenever
either stream emits.

**Completion:** Completes when **both** streams have completed.
**Errors:** The first failure from either stream fails the result.

## Signatures

```ts
export declare const zipLatestWith: {
    <AL, AR, ER, RR, B>(that: Fx<AR, ER, RR>, f: (left: AL, right: AR) => B): <EL, RL>(self: Fx<AL, EL, RL>) => Fx<B, EL | ER, RL | RR>;
    <AL, EL, RL, AR, ER, RR, B>(self: Fx<AL, EL, RL>, that: Fx<AR, ER, RR>, f: (left: AL, right: AR) => B): Fx<B, EL | ER, RL | RR>;
};
```

## Why

`zipLatestWith` projects latest-value pairs whenever either initialized source updates. The
synchronous callback changes payloads without changing `zipLatest` cardinality.

## Ownership and lifetime

Both concurrent sources and their retained latest values are owned by the consumer. The combiner
is pure; failure, services, completion, and interruption come from the inputs.

## Examples

```ts
import { Fx } from "@typed/fx"
const label = Fx.zipLatestWith(Fx.succeed(1), Fx.succeed("item"), (n, kind) => `${kind}-${n}`)
```
