fp-pack 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -90,7 +90,7 @@ There's no framework and no heavy abstractions—just well-chosen helpers that m
90
90
  `pipe` (sync) and `pipeAsync` (async) are the primary composition tools. All utilities are designed to work seamlessly in pipe chains.
91
91
 
92
92
  - **Pragmatic error handling**
93
- The `SideEffect` pattern handles errors and side effects declaratively in `pipeSideEffect`/`pipeAsyncSideEffect` pipelines. Write normal functions that compose naturally—these pipelines automatically short-circuit when they encounter a `SideEffect`, eliminating the need for wrapper types everywhere. For strict union typing across branches, use `pipeSideEffectStrict` / `pipeAsyncSideEffectStrict`. Use `runPipeResult`/`matchSideEffect` **outside** the pipeline. If the result type is widened (e.g. `SideEffect<any>`), provide generics to recover a safe union. Use `isSideEffect` for precise runtime narrowing.
93
+ The `SideEffect` pattern handles errors and side effects declaratively in `pipeSideEffect`/`pipeAsyncSideEffect` pipelines. Write normal functions that compose naturally—these pipelines automatically short-circuit when they encounter a `SideEffect`, eliminating the need for wrapper types everywhere. For strict union typing across branches, use `pipeSideEffectStrict` / `pipeAsyncSideEffectStrict`. Use `runPipeResult`/`matchSideEffect` **outside** the pipeline. If the input is narrowed to `SideEffect<R>` (e.g. after `isSideEffect`), `runPipeResult` returns `R`. If the result type is widened (e.g. `SideEffect<any>`), provide generics to recover a safe union. Use `isSideEffect` for precise runtime narrowing.
94
94
 
95
95
  - **Immutable & Pure by default**
96
96
  Core utilities avoid mutations and side effects. Any exception is explicitly named (e.g. `tap`, `log`).
@@ -330,7 +330,7 @@ Functions for composing and transforming other functions.
330
330
  - **SideEffect** - Side effect container for SideEffect-aware pipelines
331
331
  - **isSideEffect** - Type guard for runtime checking whether a value is a SideEffect
332
332
  - **matchSideEffect** - Pattern match on value or SideEffect
333
- - **runPipeResult** - Execute SideEffect or return value (call OUTSIDE pipelines). If the input is widened to `SideEffect<any>`/`any`, the result becomes `any`; provide explicit type parameters `runPipeResult<SuccessType, ErrorType>` to recover a safe union. Use `isSideEffect` for precise type narrowing.
333
+ - **runPipeResult** - Execute SideEffect or return value (call OUTSIDE pipelines). If the input is widened to `SideEffect<any>`/`any`, the result becomes `any`; provide explicit type parameters `runPipeResult<SuccessType, ErrorType>` to recover a safe union. When the input is narrowed to `SideEffect<R>` (e.g. after `isSideEffect`), `runPipeResult` returns `R`. Use `isSideEffect` for precise type narrowing.
334
334
 
335
335
  ### Control Flow
336
336
 
@@ -572,7 +572,7 @@ const result = runPipeResult(paymentPipeline(userCard));
572
572
  **Type-safe result handling with `isSideEffect`:**
573
573
 
574
574
  ```typescript
575
- import { pipeSideEffect, SideEffect, isSideEffect, runPipeResult } from 'fp-pack';
575
+ import { pipeSideEffect, pipeSideEffectStrict, SideEffect, isSideEffect, runPipeResult } from 'fp-pack';
576
576
 
577
577
  const processNumbers = pipeSideEffect(
578
578
  (nums: number[]) => nums.filter(n => n % 2 === 1),
@@ -595,6 +595,16 @@ if (!isSideEffect(oddsDoubled)) {
595
595
  console.log(`Error: ${error}`); // error: any
596
596
  }
597
597
 
598
+ // ✅ If you have a precise SideEffect type, runPipeResult returns the effect type
599
+ const strictResult = pipeSideEffectStrict(
600
+ (n: number) => (n > 0 ? n : SideEffect.of(() => 'LOW' as const))
601
+ )(-1);
602
+
603
+ if (isSideEffect(strictResult)) {
604
+ const error = runPipeResult(strictResult);
605
+ // error: 'LOW'
606
+ }
607
+
598
608
  // ⚠️ If the result type is widened, inference is lost
599
609
  const widened: number[] | SideEffect<any> = oddsDoubled;
600
610
  const unsafeResult = runPipeResult(widened); // result: any
@@ -610,6 +620,7 @@ const safeResult = runPipeResult<number[], string>(oddsDoubled); // result: num
610
620
  - ✅ **Precise input types**: `T | SideEffect<'E'>` preserves `T | 'E'` without extra annotations.
611
621
  - ⚠️ **Widened inputs**: `T | SideEffect<any>` (or `any`) collapses to `any`.
612
622
  - ✅ **With generics**: `runPipeResult<SuccessType, ErrorType>(result)` restores a safe union when inference is lost.
623
+ - ✅ **After narrowing**: If the input is `SideEffect<'E'>` (e.g. inside `if (isSideEffect(...))`), `runPipeResult` returns `'E'`.
613
624
  - ✅ **With isSideEffect**: Use for runtime checking and precise narrowing.
614
625
 
615
626
  Provide generics when inference is lost; prefer `isSideEffect` for precise narrowing.