@nlozgachev/pipelined 0.6.4 → 0.7.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.
Files changed (60) hide show
  1. package/esm/src/Core/Logged.js +111 -0
  2. package/esm/src/Core/Option.js +4 -1
  3. package/esm/src/Core/Predicate.js +133 -0
  4. package/esm/src/Core/Refinement.js +115 -0
  5. package/esm/src/Core/RemoteData.js +3 -0
  6. package/esm/src/Core/Result.js +4 -0
  7. package/esm/src/Core/State.js +181 -0
  8. package/esm/src/Core/Task.js +36 -0
  9. package/esm/src/Core/TaskOption.js +1 -0
  10. package/esm/src/Core/TaskResult.js +2 -0
  11. package/esm/src/Core/TaskValidation.js +5 -1
  12. package/esm/src/Core/These.js +4 -0
  13. package/esm/src/Core/Validation.js +4 -0
  14. package/esm/src/Core/index.js +4 -0
  15. package/package.json +1 -1
  16. package/script/src/Core/Logged.js +114 -0
  17. package/script/src/Core/Option.js +4 -1
  18. package/script/src/Core/Predicate.js +136 -0
  19. package/script/src/Core/Refinement.js +118 -0
  20. package/script/src/Core/RemoteData.js +3 -0
  21. package/script/src/Core/Result.js +4 -0
  22. package/script/src/Core/State.js +184 -0
  23. package/script/src/Core/Task.js +36 -0
  24. package/script/src/Core/TaskOption.js +1 -0
  25. package/script/src/Core/TaskResult.js +2 -0
  26. package/script/src/Core/TaskValidation.js +5 -1
  27. package/script/src/Core/These.js +4 -0
  28. package/script/src/Core/Validation.js +4 -0
  29. package/script/src/Core/index.js +4 -0
  30. package/types/src/Composition/on.d.ts.map +1 -1
  31. package/types/src/Core/InternalTypes.d.ts +3 -0
  32. package/types/src/Core/InternalTypes.d.ts.map +1 -1
  33. package/types/src/Core/Logged.d.ts +126 -0
  34. package/types/src/Core/Logged.d.ts.map +1 -0
  35. package/types/src/Core/Option.d.ts +6 -3
  36. package/types/src/Core/Option.d.ts.map +1 -1
  37. package/types/src/Core/Predicate.d.ts +161 -0
  38. package/types/src/Core/Predicate.d.ts.map +1 -0
  39. package/types/src/Core/Refinement.d.ts +138 -0
  40. package/types/src/Core/Refinement.d.ts.map +1 -0
  41. package/types/src/Core/RemoteData.d.ts +5 -2
  42. package/types/src/Core/RemoteData.d.ts.map +1 -1
  43. package/types/src/Core/Result.d.ts +7 -3
  44. package/types/src/Core/Result.d.ts.map +1 -1
  45. package/types/src/Core/State.d.ts +192 -0
  46. package/types/src/Core/State.d.ts.map +1 -0
  47. package/types/src/Core/Task.d.ts +30 -0
  48. package/types/src/Core/Task.d.ts.map +1 -1
  49. package/types/src/Core/TaskOption.d.ts +2 -1
  50. package/types/src/Core/TaskOption.d.ts.map +1 -1
  51. package/types/src/Core/TaskResult.d.ts +4 -2
  52. package/types/src/Core/TaskResult.d.ts.map +1 -1
  53. package/types/src/Core/TaskValidation.d.ts +4 -2
  54. package/types/src/Core/TaskValidation.d.ts.map +1 -1
  55. package/types/src/Core/These.d.ts +6 -2
  56. package/types/src/Core/These.d.ts.map +1 -1
  57. package/types/src/Core/Validation.d.ts +7 -3
  58. package/types/src/Core/Validation.d.ts.map +1 -1
  59. package/types/src/Core/index.d.ts +4 -0
  60. package/types/src/Core/index.d.ts.map +1 -1
@@ -87,6 +87,7 @@ export var TaskValidation;
87
87
  TaskValidation.match = (cases) => (data) => Task.map(Validation.match(cases))(data);
88
88
  /**
89
89
  * Returns the success value or a default value if the TaskValidation is invalid.
90
+ * The default can be a different type, widening the result to `Task<A | B>`.
90
91
  */
91
92
  TaskValidation.getOrElse = (defaultValue) => (data) => Task.map(Validation.getOrElse(defaultValue))(data);
92
93
  /**
@@ -96,6 +97,9 @@ export var TaskValidation;
96
97
  TaskValidation.tap = (f) => (data) => Task.map(Validation.tap(f))(data);
97
98
  /**
98
99
  * Recovers from an Invalid state by providing a fallback TaskValidation.
100
+ * The fallback can produce a different success type, widening the result to `TaskValidation<E, A | B>`.
99
101
  */
100
- TaskValidation.recover = (fallback) => (data) => Task.chain((validation) => Validation.isValid(validation) ? Task.resolve(validation) : fallback())(data);
102
+ TaskValidation.recover = (fallback) => (data) => Task.chain((validation) => Validation.isValid(validation)
103
+ ? Task.resolve(validation)
104
+ : fallback())(data);
101
105
  })(TaskValidation || (TaskValidation = {}));
@@ -184,23 +184,27 @@ export var These;
184
184
  };
185
185
  /**
186
186
  * Returns the first value, or a default if the These has no first value.
187
+ * The default can be a different type, widening the result to `A | C`.
187
188
  *
188
189
  * @example
189
190
  * ```ts
190
191
  * pipe(These.first(5), These.getFirstOrElse(0)); // 5
191
192
  * pipe(These.both(5, "warn"), These.getFirstOrElse(0)); // 5
192
193
  * pipe(These.second("warn"), These.getFirstOrElse(0)); // 0
194
+ * pipe(These.second("warn"), These.getFirstOrElse(null)); // null — typed as number | null
193
195
  * ```
194
196
  */
195
197
  These.getFirstOrElse = (defaultValue) => (data) => These.hasFirst(data) ? data.first : defaultValue;
196
198
  /**
197
199
  * Returns the second value, or a default if the These has no second value.
200
+ * The default can be a different type, widening the result to `B | D`.
198
201
  *
199
202
  * @example
200
203
  * ```ts
201
204
  * pipe(These.second("warn"), These.getSecondOrElse("none")); // "warn"
202
205
  * pipe(These.both(5, "warn"), These.getSecondOrElse("none")); // "warn"
203
206
  * pipe(These.first(5), These.getSecondOrElse("none")); // "none"
207
+ * pipe(These.first(5), These.getSecondOrElse(null)); // null — typed as string | null
204
208
  * ```
205
209
  */
206
210
  These.getSecondOrElse = (defaultValue) => (data) => These.hasSecond(data) ? data.second : defaultValue;
@@ -132,11 +132,13 @@ export var Validation;
132
132
  Validation.match = (cases) => (data) => Validation.isValid(data) ? cases.valid(data.value) : cases.invalid(data.errors);
133
133
  /**
134
134
  * Returns the success value or a default value if the Validation is invalid.
135
+ * The default can be a different type, widening the result to `A | B`.
135
136
  *
136
137
  * @example
137
138
  * ```ts
138
139
  * pipe(Validation.valid(5), Validation.getOrElse(0)); // 5
139
140
  * pipe(Validation.invalid("oops"), Validation.getOrElse(0)); // 0
141
+ * pipe(Validation.invalid("oops"), Validation.getOrElse(null)); // null — typed as number | null
140
142
  * ```
141
143
  */
142
144
  Validation.getOrElse = (defaultValue) => (data) => Validation.isValid(data) ? data.value : defaultValue;
@@ -159,10 +161,12 @@ export var Validation;
159
161
  };
160
162
  /**
161
163
  * Recovers from an Invalid state by providing a fallback Validation.
164
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
162
165
  */
163
166
  Validation.recover = (fallback) => (data) => Validation.isValid(data) ? data : fallback();
164
167
  /**
165
168
  * Recovers from an Invalid state unless the errors contain any of the blocked errors.
169
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
166
170
  */
167
171
  Validation.recoverUnless = (blockedErrors, fallback) => (data) => Validation.isInvalid(data) &&
168
172
  !data.errors.some((err) => blockedErrors.includes(err))
@@ -1,11 +1,15 @@
1
1
  export * from "./Arr.js";
2
+ export * from "./Logged.js";
2
3
  export * from "./Deferred.js";
3
4
  export * from "./Lens.js";
4
5
  export * from "./Option.js";
5
6
  export * from "./Reader.js";
6
7
  export * from "./Optional.js";
7
8
  export * from "./Rec.js";
9
+ export * from "./Predicate.js";
10
+ export * from "./Refinement.js";
8
11
  export * from "./RemoteData.js";
12
+ export * from "./State.js";
9
13
  export * from "./Result.js";
10
14
  export * from "./Task.js";
11
15
  export * from "./TaskOption.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nlozgachev/pipelined",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "Simple functional programming toolkit for TypeScript",
5
5
  "keywords": [
6
6
  "functional",
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Logged = void 0;
4
+ var Logged;
5
+ (function (Logged) {
6
+ /**
7
+ * Wraps a pure value into a `Logged` with an empty log.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * Logged.make<string, number>(42); // { value: 42, log: [] }
12
+ * ```
13
+ */
14
+ Logged.make = (value) => ({ value, log: [] });
15
+ /**
16
+ * Creates a `Logged` that records a single log entry and produces no
17
+ * meaningful value. Use this to append to the log inside a `chain`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * Logged.tell("operation completed"); // { value: undefined, log: ["operation completed"] }
22
+ * ```
23
+ */
24
+ Logged.tell = (entry) => ({ value: undefined, log: [entry] });
25
+ /**
26
+ * Transforms the value inside a `Logged` without affecting the log.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * pipe(
31
+ * Logged.of<string, number>(5),
32
+ * Logged.map(n => n * 2),
33
+ * ); // { value: 10, log: [] }
34
+ * ```
35
+ */
36
+ Logged.map = (f) => (data) => ({
37
+ value: f(data.value),
38
+ log: data.log,
39
+ });
40
+ /**
41
+ * Sequences two `Logged` computations, concatenating their logs.
42
+ * The value from the first is passed to `f`; the resulting log entries are
43
+ * appended after the entries from the first.
44
+ *
45
+ * Data-last — the first computation is the data being piped.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const result = pipe(
50
+ * Logged.of<string, number>(1),
51
+ * Logged.chain(n => pipe(Logged.tell("step"), Logged.map(() => n + 1))),
52
+ * Logged.chain(n => pipe(Logged.tell("done"), Logged.map(() => n * 10))),
53
+ * );
54
+ *
55
+ * Logged.run(result); // [20, ["step", "done"]]
56
+ * ```
57
+ */
58
+ Logged.chain = (f) => (data) => {
59
+ const next = f(data.value);
60
+ return { value: next.value, log: [...data.log, ...next.log] };
61
+ };
62
+ /**
63
+ * Applies a function wrapped in a `Logged` to a value wrapped in a `Logged`,
64
+ * concatenating both logs.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const fn: Logged<string, (n: number) => number> = {
69
+ * value: n => n * 2,
70
+ * log: ["fn-loaded"],
71
+ * };
72
+ * const arg: Logged<string, number> = { value: 5, log: ["arg-loaded"] };
73
+ *
74
+ * const result = pipe(fn, Logged.ap(arg));
75
+ * Logged.run(result); // [10, ["fn-loaded", "arg-loaded"]]
76
+ * ```
77
+ */
78
+ Logged.ap = (arg) => (data) => ({
79
+ value: data.value(arg.value),
80
+ log: [...data.log, ...arg.log],
81
+ });
82
+ /**
83
+ * Runs a side effect on the value without changing the `Logged`.
84
+ * Useful for debugging or inspecting intermediate values.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * pipe(
89
+ * Logged.of<string, number>(42),
90
+ * Logged.tap(n => console.log("value:", n)),
91
+ * );
92
+ * ```
93
+ */
94
+ Logged.tap = (f) => (data) => {
95
+ f(data.value);
96
+ return data;
97
+ };
98
+ /**
99
+ * Extracts the value and log as a `readonly [A, ReadonlyArray<W>]` tuple.
100
+ * Use this at the boundary where you need to consume both.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const result = pipe(
105
+ * Logged.of<string, number>(1),
106
+ * Logged.chain(n => pipe(Logged.tell("incremented"), Logged.map(() => n + 1))),
107
+ * );
108
+ *
109
+ * const [value, log] = Logged.run(result);
110
+ * // value = 2, log = ["incremented"]
111
+ * ```
112
+ */
113
+ Logged.run = (data) => [data.value, data.log];
114
+ })(Logged || (exports.Logged = Logged = {}));
@@ -130,12 +130,14 @@ var Option;
130
130
  */
131
131
  Option.match = (cases) => (data) => Option.isSome(data) ? cases.some(data.value) : cases.none();
132
132
  /**
133
- * Returns the value inside a Option, or a default value if None.
133
+ * Returns the value inside an Option, or a default value if None.
134
+ * The default can be a different type, widening the result to `A | B`.
134
135
  *
135
136
  * @example
136
137
  * ```ts
137
138
  * pipe(Option.some(5), Option.getOrElse(0)); // 5
138
139
  * pipe(Option.none(), Option.getOrElse(0)); // 0
140
+ * pipe(Option.none<string>(), Option.getOrElse(null)); // null — typed as string | null
139
141
  * ```
140
142
  */
141
143
  Option.getOrElse = (defaultValue) => (data) => Option.isSome(data) ? data.value : defaultValue;
@@ -170,6 +172,7 @@ var Option;
170
172
  Option.filter = (predicate) => (data) => Option.isSome(data) && predicate(data.value) ? data : Option.none();
171
173
  /**
172
174
  * Recovers from a None by providing a fallback Option.
175
+ * The fallback can produce a different type, widening the result to `Option<A | B>`.
173
176
  */
174
177
  Option.recover = (fallback) => (data) => Option.isSome(data) ? data : fallback();
175
178
  /**
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Predicate = void 0;
4
+ var Predicate;
5
+ (function (Predicate) {
6
+ /**
7
+ * Negates a predicate: the result passes exactly when the original fails.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const isBlank: Predicate<string> = s => s.trim().length === 0;
12
+ * const isNotBlank = Predicate.not(isBlank);
13
+ *
14
+ * isNotBlank("hello"); // true
15
+ * isNotBlank(" "); // false
16
+ * ```
17
+ */
18
+ Predicate.not = (p) => (a) => !p(a);
19
+ /**
20
+ * Combines two predicates with logical AND: passes only when both hold.
21
+ *
22
+ * Data-last — the first predicate is the data being piped.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const isPositive: Predicate<number> = n => n > 0;
27
+ * const isEven: Predicate<number> = n => n % 2 === 0;
28
+ *
29
+ * const isPositiveEven: Predicate<number> = pipe(isPositive, Predicate.and(isEven));
30
+ *
31
+ * isPositiveEven(4); // true
32
+ * isPositiveEven(3); // false — positive but odd
33
+ * isPositiveEven(-2); // false — even but not positive
34
+ * ```
35
+ */
36
+ Predicate.and = (second) => (first) => (a) => first(a) && second(a);
37
+ /**
38
+ * Combines two predicates with logical OR: passes when either holds.
39
+ *
40
+ * Data-last — the first predicate is the data being piped.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const isChild: Predicate<number> = n => n < 13;
45
+ * const isSenior: Predicate<number> = n => n >= 65;
46
+ *
47
+ * const getsDiscount: Predicate<number> = pipe(isChild, Predicate.or(isSenior));
48
+ *
49
+ * getsDiscount(8); // true
50
+ * getsDiscount(70); // true
51
+ * getsDiscount(30); // false
52
+ * ```
53
+ */
54
+ Predicate.or = (second) => (first) => (a) => first(a) || second(a);
55
+ /**
56
+ * Adapts a `Predicate<A>` to work on a different input type `B` by applying `f`
57
+ * to extract the relevant `A` from a `B` before running the check.
58
+ *
59
+ * Data-last — the predicate is the data being piped; `f` is the extractor.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * type User = { name: string; age: number };
64
+ *
65
+ * const isAdult: Predicate<number> = n => n >= 18;
66
+ *
67
+ * // Lift isAdult to work on Users by extracting the age field
68
+ * const isAdultUser: Predicate<User> = pipe(
69
+ * isAdult,
70
+ * Predicate.using((u: User) => u.age)
71
+ * );
72
+ *
73
+ * isAdultUser({ name: "Alice", age: 30 }); // true
74
+ * isAdultUser({ name: "Bob", age: 15 }); // false
75
+ * ```
76
+ */
77
+ Predicate.using = (f) => (p) => (b) => p(f(b));
78
+ /**
79
+ * Combines an array of predicates with AND: passes only when every predicate holds.
80
+ * Returns `true` for an empty array (vacuous truth).
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * const checks: Predicate<string>[] = [
85
+ * s => s.length > 0,
86
+ * s => s.length <= 100,
87
+ * s => !s.includes("<"),
88
+ * ];
89
+ *
90
+ * Predicate.all(checks)("hello"); // true
91
+ * Predicate.all(checks)(""); // false — too short
92
+ * Predicate.all(checks)("<b>"); // false — contains "<"
93
+ * Predicate.all([])("anything"); // true
94
+ * ```
95
+ */
96
+ Predicate.all = (predicates) => (a) => predicates.every((p) => p(a));
97
+ /**
98
+ * Combines an array of predicates with OR: passes when at least one holds.
99
+ * Returns `false` for an empty array.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * const acceptedFormats: Predicate<string>[] = [
104
+ * s => s.endsWith(".jpg"),
105
+ * s => s.endsWith(".png"),
106
+ * s => s.endsWith(".webp"),
107
+ * ];
108
+ *
109
+ * Predicate.any(acceptedFormats)("photo.jpg"); // true
110
+ * Predicate.any(acceptedFormats)("photo.gif"); // false
111
+ * Predicate.any([])("anything"); // false
112
+ * ```
113
+ */
114
+ Predicate.any = (predicates) => (a) => predicates.some((p) => p(a));
115
+ /**
116
+ * Converts a `Refinement<A, B>` into a `Predicate<A>`, discarding the compile-time
117
+ * narrowing. Use this when you want to combine a type guard with plain predicates
118
+ * using `and`, `or`, or `all`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const isString: Refinement<unknown, string> =
123
+ * Refinement.make(x => typeof x === "string");
124
+ *
125
+ * const isShortString: Predicate<unknown> = pipe(
126
+ * Predicate.fromRefinement(isString),
127
+ * Predicate.and(x => (x as string).length < 10)
128
+ * );
129
+ *
130
+ * isShortString("hi"); // true
131
+ * isShortString("a very long string that exceeds ten characters"); // false
132
+ * isShortString(42); // false
133
+ * ```
134
+ */
135
+ Predicate.fromRefinement = (r) => r;
136
+ })(Predicate || (exports.Predicate = Predicate = {}));
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Refinement = void 0;
4
+ const Option_js_1 = require("./Option.js");
5
+ const Result_js_1 = require("./Result.js");
6
+ var Refinement;
7
+ (function (Refinement) {
8
+ /**
9
+ * Creates a `Refinement<A, B>` from a plain boolean predicate.
10
+ *
11
+ * This is an unsafe cast — the caller is responsible for ensuring that the
12
+ * predicate truly characterises values of type `B`. Use this only when
13
+ * bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
14
+ * derived refinements from existing ones.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * type PositiveNumber = number & { readonly _tag: "PositiveNumber" };
19
+ *
20
+ * const isPositive: Refinement<number, PositiveNumber> =
21
+ * Refinement.make(n => n > 0);
22
+ * ```
23
+ */
24
+ Refinement.make = (f) => f;
25
+ /**
26
+ * Chains two refinements: if `ab` narrows `A` to `B` and `bc` narrows `B` to `C`,
27
+ * the result narrows `A` directly to `C`.
28
+ *
29
+ * Data-last — the first refinement `ab` is the data being piped.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
34
+ * type TrimmedString = NonEmptyString & { readonly _tag: "Trimmed" };
35
+ *
36
+ * const isNonEmpty: Refinement<string, NonEmptyString> =
37
+ * Refinement.make(s => s.length > 0);
38
+ * const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
39
+ * Refinement.make(s => s === s.trim());
40
+ *
41
+ * const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
42
+ * isNonEmpty,
43
+ * Refinement.compose(isTrimmed)
44
+ * );
45
+ * ```
46
+ */
47
+ Refinement.compose = (bc) => (ab) => (a) => ab(a) && bc(a);
48
+ /**
49
+ * Intersects two refinements: the result narrows `A` to `B & C`, passing only
50
+ * when both refinements hold simultaneously.
51
+ *
52
+ * Data-last — the first refinement is the data being piped.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
57
+ * const isNonEmpty: Refinement<unknown, { length: number }> =
58
+ * Refinement.make(x => (x as any).length > 0);
59
+ *
60
+ * const isNonEmptyString = pipe(isString, Refinement.and(isNonEmpty));
61
+ * isNonEmptyString("hi"); // true
62
+ * isNonEmptyString(""); // false
63
+ * ```
64
+ */
65
+ Refinement.and = (second) => (first) => (a) => first(a) && second(a);
66
+ /**
67
+ * Unions two refinements: the result narrows `A` to `B | C`, passing when either
68
+ * refinement holds.
69
+ *
70
+ * Data-last — the first refinement is the data being piped.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
75
+ * const isNumber: Refinement<unknown, number> = Refinement.make(x => typeof x === "number");
76
+ *
77
+ * const isStringOrNumber = pipe(isString, Refinement.or(isNumber));
78
+ * isStringOrNumber("hi"); // true
79
+ * isStringOrNumber(42); // true
80
+ * isStringOrNumber(true); // false
81
+ * ```
82
+ */
83
+ Refinement.or = (second) => (first) => (a) => first(a) || second(a);
84
+ /**
85
+ * Converts a `Refinement<A, B>` into a function `(a: A) => Option<B>`.
86
+ *
87
+ * Returns `Some(a)` when the refinement holds, `None` otherwise. Useful for
88
+ * integrating runtime validation into an `Option`-based pipeline.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * type PositiveNumber = number & { readonly _tag: "Positive" };
93
+ * const isPositive: Refinement<number, PositiveNumber> =
94
+ * Refinement.make(n => n > 0);
95
+ *
96
+ * pipe(-1, Refinement.toFilter(isPositive)); // None
97
+ * pipe(42, Refinement.toFilter(isPositive)); // Some(42)
98
+ * ```
99
+ */
100
+ Refinement.toFilter = (r) => (a) => r(a) ? Option_js_1.Option.some(a) : Option_js_1.Option.none();
101
+ /**
102
+ * Converts a `Refinement<A, B>` into a function `(a: A) => Result<E, B>`.
103
+ *
104
+ * Returns `Ok(a)` when the refinement holds, `Err(onFail(a))` otherwise. Use
105
+ * this to surface validation failures as typed errors inside a `Result` pipeline.
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
110
+ * const isNonEmpty: Refinement<string, NonEmptyString> =
111
+ * Refinement.make(s => s.length > 0);
112
+ *
113
+ * pipe("", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Err(...)
114
+ * pipe("hi", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Ok("hi")
115
+ * ```
116
+ */
117
+ Refinement.toResult = (r, onFail) => (a) => r(a) ? Result_js_1.Result.ok(a) : Result_js_1.Result.err(onFail(a));
118
+ })(Refinement || (exports.Refinement = Refinement = {}));
@@ -156,11 +156,13 @@ var RemoteData;
156
156
  };
157
157
  /**
158
158
  * Returns the success value or a default value if the RemoteData is not Success.
159
+ * The default can be a different type, widening the result to `A | B`.
159
160
  *
160
161
  * @example
161
162
  * ```ts
162
163
  * pipe(RemoteData.success(5), RemoteData.getOrElse(0)); // 5
163
164
  * pipe(RemoteData.loading(), RemoteData.getOrElse(0)); // 0
165
+ * pipe(RemoteData.loading<string, number>(), RemoteData.getOrElse(null)); // null — typed as number | null
164
166
  * ```
165
167
  */
166
168
  RemoteData.getOrElse = (defaultValue) => (data) => RemoteData.isSuccess(data) ? data.value : defaultValue;
@@ -183,6 +185,7 @@ var RemoteData;
183
185
  };
184
186
  /**
185
187
  * Recovers from a Failure state by providing a fallback RemoteData.
188
+ * The fallback can produce a different success type, widening the result to `RemoteData<E, A | B>`.
186
189
  */
187
190
  RemoteData.recover = (fallback) => (data) => RemoteData.isFailure(data) ? fallback(data.error) : data;
188
191
  /**
@@ -105,11 +105,13 @@ var Result;
105
105
  Result.match = (cases) => (data) => Result.isOk(data) ? cases.ok(data.value) : cases.err(data.error);
106
106
  /**
107
107
  * Returns the success value or a default value if the Result is an error.
108
+ * The default can be a different type, widening the result to `A | B`.
108
109
  *
109
110
  * @example
110
111
  * ```ts
111
112
  * pipe(Result.ok(5), Result.getOrElse(0)); // 5
112
113
  * pipe(Result.err("error"), Result.getOrElse(0)); // 0
114
+ * pipe(Result.err("error"), Result.getOrElse(null)); // null — typed as number | null
113
115
  * ```
114
116
  */
115
117
  Result.getOrElse = (defaultValue) => (data) => Result.isOk(data) ? data.value : defaultValue;
@@ -133,10 +135,12 @@ var Result;
133
135
  };
134
136
  /**
135
137
  * Recovers from an error by providing a fallback Result.
138
+ * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
136
139
  */
137
140
  Result.recover = (fallback) => (data) => Result.isOk(data) ? data : fallback();
138
141
  /**
139
142
  * Recovers from an error unless it matches the blocked error.
143
+ * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
140
144
  */
141
145
  Result.recoverUnless = (blockedErr, fallback) => (data) => Result.isErr(data) && data.error !== blockedErr ? fallback() : data;
142
146
  /**