@nlozgachev/pipelined 0.36.0 → 0.37.1

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/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as Maybe, W as WithValue, c as WithLog, D as Deferred, R as Result, d as WithKind, e as WithError, f as RetryOptions, g as TimeoutOptions, h as WithTimeout, i as WithMinInterval, j as WithCooldown, k as WithConcurrency, l as WithSize, m as WithDuration, n as WithN, T as Task, o as WithErrors, p as WithFirst, q as WithSecond } from './Task-zAY4kSVB.js';
2
- export { E as Equality, a as Err, N as None, O as Ok, b as Ordering, S as Some } from './Task-zAY4kSVB.js';
1
+ import { M as Maybe, q as WithValue, k as WithLog, D as Deferred, R as Result, j as WithKind, g as WithError, c as RetryOptions, d as TimeoutOptions, p as WithTimeout, l as WithMinInterval, e as WithCooldown, W as WithConcurrency, o as WithSize, f as WithDuration, m as WithN, T as Task, i as WithFirst, n as WithSecond, h as WithErrors } from './Task-uupX7xd9.js';
2
+ export { E as Equality, a as Err, N as None, O as Ok, b as Ordering, S as Some } from './Task-uupX7xd9.js';
3
3
  import { Duration, NonEmptyList } from './types.js';
4
4
 
5
5
  /**
@@ -166,161 +166,6 @@ declare namespace Lazy {
166
166
  const tap: <A>(f: (a: A) => void) => (lazy: Lazy<A>) => Lazy<A>;
167
167
  }
168
168
 
169
- /** Keys of T for which undefined is assignable (i.e. optional fields). */
170
- type OptionalKeys<T> = {
171
- [K in keyof T]-?: undefined extends T[K] ? K : never;
172
- }[keyof T];
173
- /**
174
- * Optional<S, A> focuses on a value A inside a structure S that may or may
175
- * not be present. Like a Lens, but get returns Maybe<A>.
176
- *
177
- * Compose with other Optionals via `andThen`, or with a Lens via `andThenLens`.
178
- * Convert a Lens to an Optional with `Lens.toOptional`.
179
- *
180
- * @example
181
- * ```ts
182
- * type Profile = { username: string; bio?: string };
183
- *
184
- * const bioOpt = Optional.prop<Profile>()("bio");
185
- *
186
- * pipe(profile, Optional.get(bioOpt)); // Some("hello") or None
187
- * pipe(profile, Optional.set(bioOpt)("hello")); // new Profile with bio set
188
- * pipe(profile, Optional.modify(bioOpt)(s => s + "!")); // appends if present
189
- * ```
190
- */
191
- type Optional<S, A> = {
192
- readonly get: (s: S) => Maybe<A>;
193
- readonly set: (a: A) => (s: S) => S;
194
- };
195
- declare namespace Optional {
196
- /**
197
- * Constructs an Optional from a getter (returning Maybe<A>) and a setter.
198
- *
199
- * @example
200
- * ```ts
201
- * const firstChar = Optional.make(
202
- * (s: string) => s.length > 0 ? Maybe.some(s[0]) : Maybe.none(),
203
- * (c) => (s) => s.length > 0 ? c + s.slice(1) : s,
204
- * );
205
- * ```
206
- */
207
- const make: <S, A>(get: (s: S) => Maybe<A>, set: (a: A) => (s: S) => S) => Optional<S, A>;
208
- /**
209
- * Creates an Optional that focuses on an optional property of an object.
210
- * Only keys whose type includes undefined (i.e. `field?: T`) are accepted.
211
- * Call with the structure type first, then the key.
212
- *
213
- * @example
214
- * ```ts
215
- * type Profile = { username: string; bio?: string };
216
- * const bioOpt = Optional.prop<Profile>()("bio");
217
- * ```
218
- */
219
- const prop: <S>() => <K extends OptionalKeys<S>>(key: K) => Optional<S, NonNullable<S[K]>>;
220
- /**
221
- * Creates an Optional that focuses on an element at a given index in an array.
222
- * Returns None when the index is out of bounds; set is a no-op when out of bounds.
223
- *
224
- * @example
225
- * ```ts
226
- * const firstItem = Optional.index<string>(0);
227
- *
228
- * pipe(["a", "b"], Optional.get(firstItem)); // Some("a")
229
- * pipe([], Optional.get(firstItem)); // None
230
- * ```
231
- */
232
- const index: <A>(i: number) => Optional<A[], A>;
233
- /**
234
- * Reads the focused value from a structure, returning Maybe<A>.
235
- *
236
- * @example
237
- * ```ts
238
- * pipe(profile, Optional.get(bioOpt)); // Some("...") or None
239
- * ```
240
- */
241
- const get: <S, A>(opt: Optional<S, A>) => (s: S) => Maybe<A>;
242
- /**
243
- * Replaces the focused value within a structure.
244
- * For indexed focuses, this is a no-op when the index is out of bounds.
245
- *
246
- * @example
247
- * ```ts
248
- * pipe(profile, Optional.set(bioOpt)("hello"));
249
- * ```
250
- */
251
- const set: <S, A>(opt: Optional<S, A>) => (a: A) => (s: S) => S;
252
- /**
253
- * Applies a function to the focused value if it is present; returns the
254
- * structure unchanged if the focus is absent.
255
- *
256
- * @example
257
- * ```ts
258
- * pipe(profile, Optional.modify(bioOpt)(s => s.toUpperCase()));
259
- * ```
260
- */
261
- const modify: <S, A>(opt: Optional<S, A>) => (f: (a: A) => A) => (s: S) => S;
262
- /**
263
- * Returns the focused value or a default when the focus is absent.
264
- *
265
- * @example
266
- * ```ts
267
- * pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
268
- * ```
269
- */
270
- const getOrElse: <S, A>(opt: Optional<S, A>) => (defaultValue: () => A) => (s: S) => A;
271
- /**
272
- * Extracts a value from an Optional focus using handlers for the present
273
- * and absent cases.
274
- *
275
- * @example
276
- * ```ts
277
- * pipe(profile, Optional.fold(bioOpt)(() => "no bio", (bio) => bio.toUpperCase()));
278
- * ```
279
- */
280
- const fold: <S, A>(opt: Optional<S, A>) => <B>(onNone: () => B, onSome: (a: A) => B) => (s: S) => B;
281
- /**
282
- * Pattern matches on an Optional focus using a named-case object.
283
- *
284
- * @example
285
- * ```ts
286
- * pipe(
287
- * profile,
288
- * Optional.match(bioOpt)({ none: () => "no bio", some: (bio) => bio }),
289
- * );
290
- * ```
291
- */
292
- const match: <S, A>(opt: Optional<S, A>) => <B>(cases: {
293
- none: () => B;
294
- some: (a: A) => B;
295
- }) => (s: S) => B;
296
- /**
297
- * Composes two Optionals: focuses through the outer, then through the inner.
298
- * Returns None if either focus is absent.
299
- *
300
- * @example
301
- * ```ts
302
- * const deepOpt = pipe(
303
- * Optional.prop<User>()("address"),
304
- * Optional.andThen(Optional.prop<Address>()("landmark")),
305
- * );
306
- * ```
307
- */
308
- const andThen: <A, B>(inner: Optional<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
309
- /**
310
- * Composes an Optional with a Lens, producing an Optional.
311
- * The Lens focuses within the value found by the Optional.
312
- *
313
- * @example
314
- * ```ts
315
- * const cityOpt = pipe(
316
- * Optional.prop<User>()("address"),
317
- * Optional.andThenLens(Lens.prop<Address>()("city")),
318
- * );
319
- * ```
320
- */
321
- const andThenLens: <A, B>(inner: Lens<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
322
- }
323
-
324
169
  /**
325
170
  * Lens<S, A> focuses on a single value A inside a structure S, providing
326
171
  * a composable way to read and immutably update nested data.
@@ -561,6 +406,27 @@ declare namespace Logged {
561
406
  * ```
562
407
  */
563
408
  const run: <W, A>(data: Logged<W, A>) => readonly [A, ReadonlyArray<W>];
409
+ /**
410
+ * Lifts a Logged value into an accumulator object.
411
+ *
412
+ * @example
413
+ * ```ts
414
+ * pipe(Logged.make<string, number>(42), Logged.bindTo("value")); // Logged({ value: 42 })
415
+ * ```
416
+ */
417
+ const bindTo: <K extends string>(key: K) => <W, A>(data: Logged<W, A>) => Logged<W, { [P in K]: A; }>;
418
+ /**
419
+ * Evaluates a new Logged using the current accumulator and attaches the output to a new key.
420
+ *
421
+ * @example
422
+ * ```ts
423
+ * pipe(
424
+ * Logged.make<string, { a: number }>({ a: 1 }),
425
+ * Logged.bind("b", ({ a }) => Logged.make<string, number>(a + 1))
426
+ * ); // Logged({ value: { a: 1, b: 2 } })
427
+ * ```
428
+ */
429
+ const bind: <K extends string, W, A, B>(key: K, f: (a: A) => Logged<W, B>) => (data: Logged<W, A>) => Logged<W, A & { [P in K]: B; }>;
564
430
  }
565
431
 
566
432
  type MaybeRetry<E, O> = O extends {
@@ -1265,140 +1131,159 @@ declare namespace Op {
1265
1131
  function interpret<I, E, A, O extends AllInterpretOptions<I, E>>(op: Op<I, E, A>, options: O): InterpretResult<I, E, A, O>;
1266
1132
  }
1267
1133
 
1134
+ /** Keys of T for which undefined is assignable (i.e. optional fields). */
1135
+ type OptionalKeys<T> = {
1136
+ [K in keyof T]-?: undefined extends T[K] ? K : never;
1137
+ }[keyof T];
1268
1138
  /**
1269
- * A function from `A` to `A is B` — a type predicate paired with a runtime check.
1139
+ * Optional<S, A> focuses on a value A inside a structure S that may or may
1140
+ * not be present. Like a Lens, but get returns Maybe<A>.
1270
1141
  *
1271
- * A `Refinement<A, B>` proves at compile time that a value of type `A` is actually
1272
- * the narrower type `B extends A`, backed by a runtime boolean test. Use it to
1273
- * express domain invariants (non-empty strings, positive numbers, valid emails) as
1274
- * first-class, composable values rather than one-off type guards scattered across
1275
- * the codebase.
1142
+ * Compose with other Optionals via `andThen`, or with a Lens via `andThenLens`.
1143
+ * Convert a Lens to an Optional with `Lens.toOptional`.
1276
1144
  *
1277
1145
  * @example
1278
1146
  * ```ts
1279
- * type NonEmptyString = string & { readonly _tag: "NonEmptyString" };
1147
+ * type Profile = { username: string; bio?: string };
1280
1148
  *
1281
- * const isNonEmpty: Refinement<string, NonEmptyString> =
1282
- * Refinement.make(s => s.length > 0);
1149
+ * const bioOpt = Optional.prop<Profile>()("bio");
1283
1150
  *
1284
- * pipe(
1285
- * "hello",
1286
- * Refinement.toFilter(isNonEmpty)
1287
- * ); // Some("hello")
1151
+ * pipe(profile, Optional.get(bioOpt)); // Some("hello") or None
1152
+ * pipe(profile, Optional.set(bioOpt)("hello")); // new Profile with bio set
1153
+ * pipe(profile, Optional.modify(bioOpt)(s => s + "!")); // appends if present
1288
1154
  * ```
1289
1155
  */
1290
- type Refinement<A, B extends A> = (a: A) => a is B;
1291
- declare namespace Refinement {
1156
+ type Optional<S, A> = {
1157
+ readonly get: (s: S) => Maybe<A>;
1158
+ readonly set: (a: A) => (s: S) => S;
1159
+ };
1160
+ declare namespace Optional {
1292
1161
  /**
1293
- * Creates a `Refinement<A, B>` from a plain boolean predicate.
1294
- *
1295
- * This is an unsafe cast — the caller is responsible for ensuring that the
1296
- * predicate truly characterises values of type `B`. Use this only when
1297
- * bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
1298
- * derived refinements from existing ones.
1162
+ * Constructs an Optional from a getter (returning Maybe<A>) and a setter.
1299
1163
  *
1300
1164
  * @example
1301
1165
  * ```ts
1302
- * type PositiveNumber = number & { readonly _tag: "PositiveNumber" };
1303
- *
1304
- * const isPositive: Refinement<number, PositiveNumber> =
1305
- * Refinement.make(n => n > 0);
1166
+ * const firstChar = Optional.make(
1167
+ * (s: string) => s.length > 0 ? Maybe.some(s[0]) : Maybe.none(),
1168
+ * (c) => (s) => s.length > 0 ? c + s.slice(1) : s,
1169
+ * );
1306
1170
  * ```
1307
1171
  */
1308
- const make: <A, B extends A>(f: (a: A) => boolean) => Refinement<A, B>;
1172
+ const make: <S, A>(get: (s: S) => Maybe<A>, set: (a: A) => (s: S) => S) => Optional<S, A>;
1309
1173
  /**
1310
- * Chains two refinements: if `ab` narrows `A` to `B` and `bc` narrows `B` to `C`,
1311
- * the result narrows `A` directly to `C`.
1312
- *
1313
- * Data-last — the first refinement `ab` is the data being piped.
1174
+ * Creates an Optional that focuses on an optional property of an object.
1175
+ * Only keys whose type includes undefined (i.e. `field?: T`) are accepted.
1176
+ * Call with the structure type first, then the key.
1314
1177
  *
1315
1178
  * @example
1316
1179
  * ```ts
1317
- * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
1318
- * type TrimmedString = NonEmptyString & { readonly _tag: "Trimmed" };
1319
- *
1320
- * const isNonEmpty: Refinement<string, NonEmptyString> =
1321
- * Refinement.make(s => s.length > 0);
1322
- * const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
1323
- * Refinement.make(s => s === s.trim());
1324
- *
1325
- * const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
1326
- * isNonEmpty,
1327
- * Refinement.compose(isTrimmed)
1328
- * );
1180
+ * type Profile = { username: string; bio?: string };
1181
+ * const bioOpt = Optional.prop<Profile>()("bio");
1329
1182
  * ```
1330
1183
  */
1331
- const compose: <A, B extends A, C extends B>(bc: Refinement<B, C>) => (ab: Refinement<A, B>) => Refinement<A, C>;
1184
+ const prop: <S>() => <K extends OptionalKeys<S>>(key: K) => Optional<S, NonNullable<S[K]>>;
1332
1185
  /**
1333
- * Intersects two refinements: the result narrows `A` to `B & C`, passing only
1334
- * when both refinements hold simultaneously.
1335
- *
1336
- * Data-last — the first refinement is the data being piped.
1186
+ * Creates an Optional that focuses on an element at a given index in an array.
1187
+ * Returns None when the index is out of bounds; set is a no-op when out of bounds.
1337
1188
  *
1338
1189
  * @example
1339
1190
  * ```ts
1340
- * const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
1341
- * const isNonEmpty: Refinement<unknown, { length: number }> =
1342
- * Refinement.make(x => (x as any).length > 0);
1191
+ * const firstItem = Optional.index<string>(0);
1343
1192
  *
1344
- * const isNonEmptyString = pipe(isString, Refinement.and(isNonEmpty));
1345
- * isNonEmptyString("hi"); // true
1346
- * isNonEmptyString(""); // false
1193
+ * pipe(["a", "b"], Optional.get(firstItem)); // Some("a")
1194
+ * pipe([], Optional.get(firstItem)); // None
1347
1195
  * ```
1348
1196
  */
1349
- const and: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B & C>;
1197
+ const index: <A>(i: number) => Optional<A[], A>;
1350
1198
  /**
1351
- * Unions two refinements: the result narrows `A` to `B | C`, passing when either
1352
- * refinement holds.
1353
- *
1354
- * Data-last — the first refinement is the data being piped.
1199
+ * Reads the focused value from a structure, returning Maybe<A>.
1355
1200
  *
1356
1201
  * @example
1357
1202
  * ```ts
1358
- * const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
1359
- * const isNumber: Refinement<unknown, number> = Refinement.make(x => typeof x === "number");
1203
+ * pipe(profile, Optional.get(bioOpt)); // Some("...") or None
1204
+ * ```
1205
+ */
1206
+ const get: <S, A>(opt: Optional<S, A>) => (s: S) => Maybe<A>;
1207
+ /**
1208
+ * Replaces the focused value within a structure.
1209
+ * For indexed focuses, this is a no-op when the index is out of bounds.
1360
1210
  *
1361
- * const isStringOrNumber = pipe(isString, Refinement.or(isNumber));
1362
- * isStringOrNumber("hi"); // true
1363
- * isStringOrNumber(42); // true
1364
- * isStringOrNumber(true); // false
1211
+ * @example
1212
+ * ```ts
1213
+ * pipe(profile, Optional.set(bioOpt)("hello"));
1365
1214
  * ```
1366
1215
  */
1367
- const or: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B | C>;
1216
+ const set: <S, A>(opt: Optional<S, A>) => (a: A) => (s: S) => S;
1368
1217
  /**
1369
- * Converts a `Refinement<A, B>` into a function `(a: A) => Maybe<B>`.
1218
+ * Applies a function to the focused value if it is present; returns the
1219
+ * structure unchanged if the focus is absent.
1370
1220
  *
1371
- * Returns `Some(a)` when the refinement holds, `None` otherwise. Useful for
1372
- * integrating runtime validation into a `Maybe`-based pipeline.
1221
+ * @example
1222
+ * ```ts
1223
+ * pipe(profile, Optional.modify(bioOpt)(s => s.toUpperCase()));
1224
+ * ```
1225
+ */
1226
+ const modify: <S, A>(opt: Optional<S, A>) => (f: (a: A) => A) => (s: S) => S;
1227
+ /**
1228
+ * Returns the focused value or a default when the focus is absent.
1373
1229
  *
1374
1230
  * @example
1375
1231
  * ```ts
1376
- * type PositiveNumber = number & { readonly _tag: "Positive" };
1377
- * const isPositive: Refinement<number, PositiveNumber> =
1378
- * Refinement.make(n => n > 0);
1232
+ * pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
1233
+ * ```
1234
+ */
1235
+ const getOrElse: <S, A>(opt: Optional<S, A>) => (defaultValue: () => A) => (s: S) => A;
1236
+ /**
1237
+ * Extracts a value from an Optional focus using handlers for the present
1238
+ * and absent cases.
1379
1239
  *
1380
- * pipe(-1, Refinement.toFilter(isPositive)); // None
1381
- * pipe(42, Refinement.toFilter(isPositive)); // Some(42)
1240
+ * @example
1241
+ * ```ts
1242
+ * pipe(profile, Optional.fold(bioOpt)(() => "no bio", (bio) => bio.toUpperCase()));
1382
1243
  * ```
1383
1244
  */
1384
- const toFilter: <A, B extends A>(r: Refinement<A, B>) => (a: A) => Maybe<B>;
1245
+ const fold: <S, A>(opt: Optional<S, A>) => <B>(onNone: () => B, onSome: (a: A) => B) => (s: S) => B;
1385
1246
  /**
1386
- * Converts a `Refinement<A, B>` into a function `(a: A) => Result<E, B>`.
1247
+ * Pattern matches on an Optional focus using a named-case object.
1387
1248
  *
1388
- * Returns `Ok(a)` when the refinement holds, `Err(onFail(a))` otherwise. Use
1389
- * this to surface validation failures as typed errors inside a `Result` pipeline.
1249
+ * @example
1250
+ * ```ts
1251
+ * pipe(
1252
+ * profile,
1253
+ * Optional.match(bioOpt)({ none: () => "no bio", some: (bio) => bio }),
1254
+ * );
1255
+ * ```
1256
+ */
1257
+ const match: <S, A>(opt: Optional<S, A>) => <B>(cases: {
1258
+ none: () => B;
1259
+ some: (a: A) => B;
1260
+ }) => (s: S) => B;
1261
+ /**
1262
+ * Composes two Optionals: focuses through the outer, then through the inner.
1263
+ * Returns None if either focus is absent.
1390
1264
  *
1391
1265
  * @example
1392
1266
  * ```ts
1393
- * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
1394
- * const isNonEmpty: Refinement<string, NonEmptyString> =
1395
- * Refinement.make(s => s.length > 0);
1267
+ * const deepOpt = pipe(
1268
+ * Optional.prop<User>()("address"),
1269
+ * Optional.andThen(Optional.prop<Address>()("landmark")),
1270
+ * );
1271
+ * ```
1272
+ */
1273
+ const andThen: <A, B>(inner: Optional<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
1274
+ /**
1275
+ * Composes an Optional with a Lens, producing an Optional.
1276
+ * The Lens focuses within the value found by the Optional.
1396
1277
  *
1397
- * pipe("", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Err(...)
1398
- * pipe("hi", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Ok("hi")
1278
+ * @example
1279
+ * ```ts
1280
+ * const cityOpt = pipe(
1281
+ * Optional.prop<User>()("address"),
1282
+ * Optional.andThenLens(Lens.prop<Address>()("city")),
1283
+ * );
1399
1284
  * ```
1400
1285
  */
1401
- const toResult: <A, B extends A, E>(r: Refinement<A, B>, onFail: (a: A) => E) => (a: A) => Result<E, B>;
1286
+ const andThenLens: <A, B>(inner: Lens<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
1402
1287
  }
1403
1288
 
1404
1289
  /**
@@ -1715,6 +1600,163 @@ declare namespace Reader {
1715
1600
  * ```
1716
1601
  */
1717
1602
  const run: <R>(env: R) => <A>(data: Reader<R, A>) => A;
1603
+ /**
1604
+ * Lifts a Reader value into an accumulator object.
1605
+ *
1606
+ * @example
1607
+ * ```ts
1608
+ * pipe(Reader.resolve(42), Reader.bindTo("value")); // Reader({ value: 42 })
1609
+ * ```
1610
+ */
1611
+ const bindTo: <K extends string>(key: K) => <R, A>(data: Reader<R, A>) => Reader<R, { [P in K]: A; }>;
1612
+ /**
1613
+ * Evaluates a new Reader using the current accumulator and attaches the output to a new key.
1614
+ *
1615
+ * @example
1616
+ * ```ts
1617
+ * pipe(
1618
+ * Reader.resolve({ a: 1 }),
1619
+ * Reader.bind("b", ({ a }) => Reader.resolve(a + 1))
1620
+ * ); // Reader({ a: 1, b: 2 })
1621
+ * ```
1622
+ */
1623
+ const bind: <K extends string, R, A, B>(key: K, f: (a: A) => Reader<R, B>) => (data: Reader<R, A>) => Reader<R, A & { [P in K]: B; }>;
1624
+ }
1625
+
1626
+ /**
1627
+ * A function from `A` to `A is B` — a type predicate paired with a runtime check.
1628
+ *
1629
+ * A `Refinement<A, B>` proves at compile time that a value of type `A` is actually
1630
+ * the narrower type `B extends A`, backed by a runtime boolean test. Use it to
1631
+ * express domain invariants (non-empty strings, positive numbers, valid emails) as
1632
+ * first-class, composable values rather than one-off type guards scattered across
1633
+ * the codebase.
1634
+ *
1635
+ * @example
1636
+ * ```ts
1637
+ * type NonEmptyString = string & { readonly _tag: "NonEmptyString" };
1638
+ *
1639
+ * const isNonEmpty: Refinement<string, NonEmptyString> =
1640
+ * Refinement.make(s => s.length > 0);
1641
+ *
1642
+ * pipe(
1643
+ * "hello",
1644
+ * Refinement.toFilter(isNonEmpty)
1645
+ * ); // Some("hello")
1646
+ * ```
1647
+ */
1648
+ type Refinement<A, B extends A> = (a: A) => a is B;
1649
+ declare namespace Refinement {
1650
+ /**
1651
+ * Creates a `Refinement<A, B>` from a plain boolean predicate.
1652
+ *
1653
+ * This is an unsafe cast — the caller is responsible for ensuring that the
1654
+ * predicate truly characterises values of type `B`. Use this only when
1655
+ * bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
1656
+ * derived refinements from existing ones.
1657
+ *
1658
+ * @example
1659
+ * ```ts
1660
+ * type PositiveNumber = number & { readonly _tag: "PositiveNumber" };
1661
+ *
1662
+ * const isPositive: Refinement<number, PositiveNumber> =
1663
+ * Refinement.make(n => n > 0);
1664
+ * ```
1665
+ */
1666
+ const make: <A, B extends A>(f: (a: A) => boolean) => Refinement<A, B>;
1667
+ /**
1668
+ * Chains two refinements: if `ab` narrows `A` to `B` and `bc` narrows `B` to `C`,
1669
+ * the result narrows `A` directly to `C`.
1670
+ *
1671
+ * Data-last — the first refinement `ab` is the data being piped.
1672
+ *
1673
+ * @example
1674
+ * ```ts
1675
+ * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
1676
+ * type TrimmedString = NonEmptyString & { readonly _tag: "Trimmed" };
1677
+ *
1678
+ * const isNonEmpty: Refinement<string, NonEmptyString> =
1679
+ * Refinement.make(s => s.length > 0);
1680
+ * const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
1681
+ * Refinement.make(s => s === s.trim());
1682
+ *
1683
+ * const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
1684
+ * isNonEmpty,
1685
+ * Refinement.compose(isTrimmed)
1686
+ * );
1687
+ * ```
1688
+ */
1689
+ const compose: <A, B extends A, C extends B>(bc: Refinement<B, C>) => (ab: Refinement<A, B>) => Refinement<A, C>;
1690
+ /**
1691
+ * Intersects two refinements: the result narrows `A` to `B & C`, passing only
1692
+ * when both refinements hold simultaneously.
1693
+ *
1694
+ * Data-last — the first refinement is the data being piped.
1695
+ *
1696
+ * @example
1697
+ * ```ts
1698
+ * const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
1699
+ * const isNonEmpty: Refinement<unknown, { length: number }> =
1700
+ * Refinement.make(x => (x as any).length > 0);
1701
+ *
1702
+ * const isNonEmptyString = pipe(isString, Refinement.and(isNonEmpty));
1703
+ * isNonEmptyString("hi"); // true
1704
+ * isNonEmptyString(""); // false
1705
+ * ```
1706
+ */
1707
+ const and: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B & C>;
1708
+ /**
1709
+ * Unions two refinements: the result narrows `A` to `B | C`, passing when either
1710
+ * refinement holds.
1711
+ *
1712
+ * Data-last — the first refinement is the data being piped.
1713
+ *
1714
+ * @example
1715
+ * ```ts
1716
+ * const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
1717
+ * const isNumber: Refinement<unknown, number> = Refinement.make(x => typeof x === "number");
1718
+ *
1719
+ * const isStringOrNumber = pipe(isString, Refinement.or(isNumber));
1720
+ * isStringOrNumber("hi"); // true
1721
+ * isStringOrNumber(42); // true
1722
+ * isStringOrNumber(true); // false
1723
+ * ```
1724
+ */
1725
+ const or: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B | C>;
1726
+ /**
1727
+ * Converts a `Refinement<A, B>` into a function `(a: A) => Maybe<B>`.
1728
+ *
1729
+ * Returns `Some(a)` when the refinement holds, `None` otherwise. Useful for
1730
+ * integrating runtime validation into a `Maybe`-based pipeline.
1731
+ *
1732
+ * @example
1733
+ * ```ts
1734
+ * type PositiveNumber = number & { readonly _tag: "Positive" };
1735
+ * const isPositive: Refinement<number, PositiveNumber> =
1736
+ * Refinement.make(n => n > 0);
1737
+ *
1738
+ * pipe(-1, Refinement.toFilter(isPositive)); // None
1739
+ * pipe(42, Refinement.toFilter(isPositive)); // Some(42)
1740
+ * ```
1741
+ */
1742
+ const toFilter: <A, B extends A>(r: Refinement<A, B>) => (a: A) => Maybe<B>;
1743
+ /**
1744
+ * Converts a `Refinement<A, B>` into a function `(a: A) => Result<E, B>`.
1745
+ *
1746
+ * Returns `Ok(a)` when the refinement holds, `Err(onFail(a))` otherwise. Use
1747
+ * this to surface validation failures as typed errors inside a `Result` pipeline.
1748
+ *
1749
+ * @example
1750
+ * ```ts
1751
+ * type NonEmptyString = string & { readonly _tag: "NonEmpty" };
1752
+ * const isNonEmpty: Refinement<string, NonEmptyString> =
1753
+ * Refinement.make(s => s.length > 0);
1754
+ *
1755
+ * pipe("", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Err(...)
1756
+ * pipe("hi", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Ok("hi")
1757
+ * ```
1758
+ */
1759
+ const toResult: <A, B extends A, E>(r: Refinement<A, B>, onFail: (a: A) => E) => (a: A) => Result<E, B>;
1718
1760
  }
1719
1761
 
1720
1762
  type NotAsked = WithKind<"NotAsked">;
@@ -1962,140 +2004,7 @@ declare namespace RemoteData {
1962
2004
  }
1963
2005
 
1964
2006
  /**
1965
- * A Task that can fail with an error of type E or succeed with a value of type A.
1966
- * Combines async operations with typed error handling.
1967
- *
1968
- * @example
1969
- * ```ts
1970
- * const fetchUser = (id: string): TaskResult<Error, User> =>
1971
- * TaskResult.tryCatch(
1972
- * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
1973
- * (e) => new Error(`Failed to fetch user: ${e}`)
1974
- * );
1975
- * ```
1976
- */
1977
- type TaskResult<E, A> = Task<Result<E, A>>;
1978
- declare namespace TaskResult {
1979
- /**
1980
- * Wraps a value in a successful TaskResult.
1981
- */
1982
- const ok: <E, A>(value: A) => TaskResult<E, A>;
1983
- /**
1984
- * Creates a failed TaskResult with the given error.
1985
- */
1986
- const err: <E, A>(error: E) => TaskResult<E, A>;
1987
- /**
1988
- * Creates a TaskResult from a nullable value.
1989
- * Returns Ok if the value is not null or undefined, err from onNull otherwise.
1990
- */
1991
- const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
1992
- /**
1993
- * Creates a TaskResult from a Maybe.
1994
- * Some becomes Ok, None becomes err from onNone.
1995
- */
1996
- const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
1997
- /**
1998
- * Lifts a Result into a TaskResult.
1999
- */
2000
- const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
2001
- /**
2002
- * Wraps a Promise-returning function of any arguments, returning a new function
2003
- * that catches rejections and returns a TaskResult.
2004
- */
2005
- const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => Promise<A>, onError: (e: unknown) => E) => (...args: Args) => TaskResult<E, A>;
2006
- /**
2007
- * Creates a TaskResult from a function that may throw.
2008
- * Catches any errors and transforms them using the onError function.
2009
- * The factory optionally receives an `AbortSignal` forwarded from the call site.
2010
- *
2011
- * @example
2012
- * ```ts
2013
- * const fetchUser = (id: string): TaskResult<string, User> =>
2014
- * TaskResult.tryCatch(
2015
- * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
2016
- * String
2017
- * );
2018
- * ```
2019
- */
2020
- const tryCatch: <E, A>(f: (signal?: AbortSignal) => Promise<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
2021
- /**
2022
- * Transforms the success value inside a TaskResult.
2023
- */
2024
- const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
2025
- /**
2026
- * Transforms the error value inside a TaskResult.
2027
- */
2028
- const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
2029
- /**
2030
- * Chains TaskResult computations. If the first succeeds, passes the value to f.
2031
- * If the first fails, propagates the error.
2032
- */
2033
- const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
2034
- /**
2035
- * Extracts the value from a TaskResult by providing handlers for both cases.
2036
- */
2037
- const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
2038
- /**
2039
- * Pattern matches on a TaskResult, returning a Task of the result.
2040
- */
2041
- const match: <E, A, B>(cases: {
2042
- err: (e: E) => B;
2043
- ok: (a: A) => B;
2044
- }) => (data: TaskResult<E, A>) => Task<B>;
2045
- /**
2046
- * Recovers from an error by providing a fallback TaskResult.
2047
- * The fallback can produce a different success type, widening the result to `TaskResult<E, A | B>`.
2048
- */
2049
- const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
2050
- /**
2051
- * Returns the success value or a default value if the TaskResult is an error.
2052
- * The default can be a different type, widening the result to `Task<A | B>`.
2053
- */
2054
- const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
2055
- /**
2056
- * Executes a side effect on the success value without changing the TaskResult.
2057
- * Useful for logging or debugging.
2058
- */
2059
- const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
2060
- /**
2061
- * Executes a side effect on the error value without changing the TaskResult.
2062
- * Useful for logging or reporting async errors.
2063
- *
2064
- * @example
2065
- * ```ts
2066
- * pipe(
2067
- * fetchUser(id),
2068
- * TaskResult.tapError(e => console.error("fetch failed:", e)),
2069
- * TaskResult.chain(saveToCache),
2070
- * )
2071
- * ```
2072
- */
2073
- const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
2074
- /**
2075
- * Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
2076
- * Both Tasks run in parallel.
2077
- */
2078
- const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
2079
- /**
2080
- * Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
2081
- * Use as a terminal step in a `pipe` chain.
2082
- *
2083
- * @example
2084
- * ```ts
2085
- * const controller = new AbortController();
2086
- * const result = await pipe(
2087
- * fetchUser("42"),
2088
- * TaskResult.chain(user => fetchPosts(user.id)),
2089
- * TaskResult.run(controller.signal),
2090
- * );
2091
- * if (Result.isOk(result)) render(result.value);
2092
- * ```
2093
- */
2094
- const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Promise<Result<E, A>>;
2095
- }
2096
-
2097
- /**
2098
- * A Resource pairs an async acquisition step with a guaranteed cleanup step.
2007
+ * A Resource pairs an async acquisition step with a guaranteed cleanup step.
2099
2008
  *
2100
2009
  * Use it whenever something must be explicitly closed, released, or torn down
2101
2010
  * after you are done with it — database connections, file handles, locks,
@@ -2379,6 +2288,27 @@ declare namespace State {
2379
2288
  * ```
2380
2289
  */
2381
2290
  const execute: <S>(initialState: S) => <A>(st: State<S, A>) => S;
2291
+ /**
2292
+ * Lifts a State value into an accumulator object.
2293
+ *
2294
+ * @example
2295
+ * ```ts
2296
+ * pipe(State.resolve(42), State.bindTo("value")); // State({ value: 42 })
2297
+ * ```
2298
+ */
2299
+ const bindTo: <K extends string>(key: K) => <S, A>(data: State<S, A>) => State<S, { [P in K]: A; }>;
2300
+ /**
2301
+ * Evaluates a new State using the current accumulator and attaches the output to a new key.
2302
+ *
2303
+ * @example
2304
+ * ```ts
2305
+ * pipe(
2306
+ * State.resolve({ a: 1 }),
2307
+ * State.bind("b", ({ a }) => State.resolve(a + 1))
2308
+ * ); // State({ a: 1, b: 2 })
2309
+ * ```
2310
+ */
2311
+ const bind: <K extends string, S, A, B>(key: K, f: (a: A) => State<S, B>) => (data: State<S, A>) => State<S, A & { [P in K]: B; }>;
2382
2312
  }
2383
2313
 
2384
2314
  /**
@@ -2508,313 +2438,196 @@ declare namespace TaskMaybe {
2508
2438
  * ```
2509
2439
  */
2510
2440
  const toTaskResult: <E>(onNone: () => E) => <A>(data: TaskMaybe<A>) => TaskResult<E, A>;
2511
- }
2512
-
2513
- type Passed<A> = WithKind<"Passed"> & WithValue<A>;
2514
- type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
2515
- /**
2516
- * Validation represents a value that is either passed with a success value,
2517
- * or failed with accumulated errors.
2518
- * Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
2519
- *
2520
- * Use Validation when you need to collect all errors (e.g., form validation).
2521
- * Use Result when you want to fail fast on the first error.
2522
- *
2523
- * @example
2524
- * ```ts
2525
- * const validateName = (name: string): Validation<string, string> =>
2526
- * name.length > 0 ? Validation.passed(name) : Validation.failed("Name is required");
2527
- *
2528
- * const validateAge = (age: number): Validation<string, number> =>
2529
- * age >= 0 ? Validation.passed(age) : Validation.failed("Age must be positive");
2530
- *
2531
- * // Accumulates all errors using ap
2532
- * pipe(
2533
- * Validation.passed((name: string) => (age: number) => ({ name, age })),
2534
- * Validation.ap(validateName("")),
2535
- * Validation.ap(validateAge(-1))
2536
- * );
2537
- * // Failed(["Name is required", "Age must be positive"])
2538
- * ```
2539
- */
2540
- type Validation<E, A> = Passed<A> | Failed<E>;
2541
- declare namespace Validation {
2542
2441
  /**
2543
- * Wraps a value in a passed Validation.
2442
+ * Lifts a TaskMaybe value into an accumulator object.
2544
2443
  *
2545
2444
  * @example
2546
2445
  * ```ts
2547
- * Validation.passed(42); // Passed(42)
2446
+ * pipe(TaskMaybe.some(42), TaskMaybe.bindTo("value")); // TaskMaybe({ value: 42 })
2548
2447
  * ```
2549
2448
  */
2550
- const passed: <E, A>(value: A) => Validation<E, A>;
2449
+ const bindTo: <K extends string>(key: K) => <A>(data: TaskMaybe<A>) => TaskMaybe<{ [P in K]: A; }>;
2551
2450
  /**
2552
- * Creates a failed Validation from a single error.
2451
+ * Evaluates a new TaskMaybe using the current accumulator and attaches the output to a new key.
2553
2452
  *
2554
2453
  * @example
2555
2454
  * ```ts
2556
- * Validation.failed("Invalid input");
2455
+ * pipe(
2456
+ * TaskMaybe.some({ a: 1 }),
2457
+ * TaskMaybe.bind("b", ({ a }) => TaskMaybe.some(a + 1))
2458
+ * ); // TaskMaybe({ a: 1, b: 2 })
2557
2459
  * ```
2558
2460
  */
2559
- const failed: <E>(error: E) => Failed<E>;
2461
+ const bind: <K extends string, A, B>(key: K, f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<A & { [P in K]: B; }>;
2462
+ }
2463
+
2464
+ /**
2465
+ * A Task that can fail with an error of type E or succeed with a value of type A.
2466
+ * Combines async operations with typed error handling.
2467
+ *
2468
+ * @example
2469
+ * ```ts
2470
+ * const fetchUser = (id: string): TaskResult<Error, User> =>
2471
+ * TaskResult.tryCatch(
2472
+ * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
2473
+ * (e) => new Error(`Failed to fetch user: ${e}`)
2474
+ * );
2475
+ * ```
2476
+ */
2477
+ type TaskResult<E, A> = Task<Result<E, A>>;
2478
+ declare namespace TaskResult {
2560
2479
  /**
2561
- * Creates a failed Validation from multiple errors.
2562
- *
2563
- * @example
2564
- * ```ts
2565
- * Validation.failedAll(["Invalid input"]);
2566
- * ```
2480
+ * Wraps a value in a successful TaskResult.
2567
2481
  */
2568
- const failedAll: <E>(errors: NonEmptyList<E>) => Failed<E>;
2482
+ const ok: <E, A>(value: A) => TaskResult<E, A>;
2569
2483
  /**
2570
- * Type guard that checks if a Validation is passed.
2484
+ * Creates a failed TaskResult with the given error.
2571
2485
  */
2572
- const isPassed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
2486
+ const err: <E, A>(error: E) => TaskResult<E, A>;
2573
2487
  /**
2574
- * Type guard that checks if a Validation is failed.
2488
+ * Creates a TaskResult from a nullable value.
2489
+ * Returns Ok if the value is not null or undefined, err from onNull otherwise.
2575
2490
  */
2576
- const isFailed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
2491
+ const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
2577
2492
  /**
2578
- * Creates a Validation from a predicate applied to a value.
2579
- * Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
2580
- *
2581
- * @example
2582
- * ```ts
2583
- * const validateName = Validation.fromPredicate(
2584
- * (s: string) => s.length > 0,
2585
- * () => "Name is required"
2586
- * );
2587
- *
2588
- * validateName("Alice"); // Passed("Alice")
2589
- * validateName(""); // Failed(["Name is required"])
2590
- * ```
2493
+ * Creates a TaskResult from a Maybe.
2494
+ * Some becomes Ok, None becomes err from onNone.
2591
2495
  */
2592
- const fromPredicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
2496
+ const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
2593
2497
  /**
2594
- * Creates a Validation from a nullable value.
2595
- * If the value is null or undefined, returns Failed with the error from onNull.
2596
- * Otherwise, returns Passed.
2498
+ * Lifts a Result into a TaskResult.
2499
+ */
2500
+ const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
2501
+ /**
2502
+ * Wraps a Promise-returning function of any arguments, returning a new function
2503
+ * that catches rejections and returns a TaskResult.
2504
+ */
2505
+ const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => Promise<A>, onError: (e: unknown) => E) => (...args: Args) => TaskResult<E, A>;
2506
+ /**
2507
+ * Creates a TaskResult from a function that may throw.
2508
+ * Catches any errors and transforms them using the onError function.
2509
+ * The factory optionally receives an `AbortSignal` forwarded from the call site.
2597
2510
  *
2598
2511
  * @example
2599
2512
  * ```ts
2600
- * pipe(null, Validation.fromNullable(() => "is null")); // Failed(["is null"])
2601
- * pipe(42, Validation.fromNullable(() => "is null")); // Passed(42)
2513
+ * const fetchUser = (id: string): TaskResult<string, User> =>
2514
+ * TaskResult.tryCatch(
2515
+ * (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
2516
+ * String
2517
+ * );
2602
2518
  * ```
2603
2519
  */
2604
- const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
2520
+ const tryCatch: <E, A>(f: (signal?: AbortSignal) => Promise<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
2605
2521
  /**
2606
- * Creates a Validation from a Maybe.
2607
- * If the Maybe is None, returns Failed with the error from onNone.
2608
- * Otherwise, returns Passed.
2609
- *
2610
- * @example
2611
- * ```ts
2612
- * pipe(Maybe.none(), Validation.fromMaybe(() => "is none")); // Failed(["is none"])
2613
- * pipe(Maybe.some(42), Validation.fromMaybe(() => "is none")); // Passed(42)
2614
- * ```
2615
- */
2616
- const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
2617
- /**
2618
- * Transforms the success value inside a Validation.
2619
- *
2620
- * @example
2621
- * ```ts
2622
- * pipe(Validation.passed(5), Validation.map(n => n * 2)); // Passed(10)
2623
- * pipe(Validation.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
2624
- * ```
2522
+ * Transforms the success value inside a TaskResult.
2625
2523
  */
2626
- const map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
2524
+ const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
2627
2525
  /**
2628
- * Transforms the error list inside a Validation.
2629
- *
2630
- * @example
2631
- * ```ts
2632
- * pipe(Validation.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
2633
- * ```
2526
+ * Transforms the error value inside a TaskResult.
2634
2527
  */
2635
- const mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
2528
+ const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
2636
2529
  /**
2637
- * Applies a function wrapped in a Validation to a value wrapped in a Validation.
2638
- * Accumulates errors from both sides.
2639
- *
2640
- * @example
2641
- * ```ts
2642
- * const add = (a: number) => (b: number) => a + b;
2643
- * pipe(
2644
- * Validation.passed(add),
2645
- * Validation.ap(Validation.passed(5)),
2646
- * Validation.ap(Validation.passed(3))
2647
- * ); // Passed(8)
2648
- *
2649
- * pipe(
2650
- * Validation.passed(add),
2651
- * Validation.ap(Validation.failed<string, number>("bad a")),
2652
- * Validation.ap(Validation.failed<string, number>("bad b"))
2653
- * ); // Failed(["bad a", "bad b"])
2654
- * ```
2530
+ * Chains TaskResult computations. If the first succeeds, passes the value to f.
2531
+ * If the first fails, propagates the error.
2655
2532
  */
2656
- const ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
2533
+ const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
2657
2534
  /**
2658
- * Extracts the value from a Validation by providing handlers for both cases.
2659
- *
2660
- * @example
2661
- * ```ts
2662
- * pipe(
2663
- * Validation.passed(42),
2664
- * Validation.fold(
2665
- * errors => `Errors: ${errors.join(", ")}`,
2666
- * value => `Value: ${value}`
2667
- * )
2668
- * );
2669
- * ```
2535
+ * Extracts the value from a TaskResult by providing handlers for both cases.
2670
2536
  */
2671
- const fold: <E, A, B>(onFailed: (errors: NonEmptyList<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
2537
+ const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
2672
2538
  /**
2673
- * Pattern matches on a Validation, returning the result of the matching case.
2674
- *
2675
- * @example
2676
- * ```ts
2677
- * pipe(
2678
- * validation,
2679
- * Validation.match({
2680
- * passed: value => `Got ${value}`,
2681
- * failed: errors => `Failed: ${errors.join(", ")}`
2682
- * })
2683
- * );
2684
- * ```
2539
+ * Pattern matches on a TaskResult, returning a Task of the result.
2685
2540
  */
2686
2541
  const match: <E, A, B>(cases: {
2687
- passed: (a: A) => B;
2688
- failed: (errors: NonEmptyList<E>) => B;
2689
- }) => (data: Validation<E, A>) => B;
2690
- /**
2691
- * Returns the success value or a default value if the Validation is failed.
2692
- * The default can be a different type, widening the result to `A | B`.
2693
- *
2694
- * @example
2695
- * ```ts
2696
- * pipe(Validation.passed(5), Validation.getOrElse(() => 0)); // 5
2697
- * pipe(Validation.failed("oops"), Validation.getOrElse(() => 0)); // 0
2698
- * pipe(Validation.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
2699
- * ```
2700
- */
2701
- const getOrElse: <E, A, B>(defaultValue: () => B) => (data: Validation<E, A>) => A | B;
2542
+ err: (e: E) => B;
2543
+ ok: (a: A) => B;
2544
+ }) => (data: TaskResult<E, A>) => Task<B>;
2702
2545
  /**
2703
- * Executes a side effect on the success value without changing the Validation.
2704
- *
2705
- * @example
2706
- * ```ts
2707
- * pipe(
2708
- * Validation.passed(5),
2709
- * Validation.tap(n => console.log("Value:", n)),
2710
- * Validation.map(n => n * 2)
2711
- * );
2712
- * ```
2546
+ * Recovers from an error by providing a fallback TaskResult.
2547
+ * The fallback can produce a different success type, widening the result to `TaskResult<E, A | B>`.
2713
2548
  */
2714
- const tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
2549
+ const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
2715
2550
  /**
2716
- * Executes a side effect on the accumulated errors without changing the Validation.
2717
- * Useful for logging or reporting validation failures.
2718
- *
2719
- * @example
2720
- * ```ts
2721
- * pipe(
2722
- * Validation.failed("Name required"),
2723
- * Validation.tapError(errors => console.error("validation failed:", errors)),
2724
- * Validation.map(toUser)
2725
- * );
2726
- * ```
2551
+ * Returns the success value or a default value if the TaskResult is an error.
2552
+ * The default can be a different type, widening the result to `Task<A | B>`.
2727
2553
  */
2728
- const tapError: <E, A>(f: (errors: NonEmptyList<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
2554
+ const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
2729
2555
  /**
2730
- * Recovers from a Failed state by providing a fallback Validation.
2731
- * The fallback receives the accumulated error list so callers can inspect which errors occurred.
2732
- * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
2556
+ * Executes a side effect on the success value without changing the TaskResult.
2557
+ * Useful for logging or debugging.
2733
2558
  */
2734
- const recover: <E, A, B>(fallback: (errors: NonEmptyList<E>) => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
2559
+ const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
2735
2560
  /**
2736
- * Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
2737
- * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
2561
+ * Executes a side effect on the error value without changing the TaskResult.
2562
+ * Useful for logging or reporting async errors.
2738
2563
  *
2739
2564
  * @example
2740
2565
  * ```ts
2741
2566
  * pipe(
2742
- * Validation.failed("field-error"),
2743
- * Validation.recoverUnless(e => e === "fatal", () => Validation.passed(0))
2744
- * ); // Passed(0)
2567
+ * fetchUser(id),
2568
+ * TaskResult.tapError(e => console.error("fetch failed:", e)),
2569
+ * TaskResult.chain(saveToCache),
2570
+ * )
2745
2571
  * ```
2746
2572
  */
2747
- const recoverUnless: <E, A, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
2573
+ const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
2748
2574
  /**
2749
- * Converts a Validation to a Result.
2750
- * Passed becomes Ok, Failed becomes Err with the accumulated error list.
2751
- *
2752
- * @example
2753
- * ```ts
2754
- * Validation.toResult(Validation.passed(42)); // Ok(42)
2755
- * Validation.toResult(Validation.failed("oops")); // Err(["oops"])
2756
- * ```
2575
+ * Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
2576
+ * Both Tasks run in parallel.
2757
2577
  */
2758
- const toResult: <E, A>(data: Validation<E, A>) => Result<NonEmptyList<E>, A>;
2578
+ const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
2759
2579
  /**
2760
- * Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
2761
- * (errors are discarded).
2580
+ * Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
2581
+ * Use as a terminal step in a `pipe` chain.
2762
2582
  *
2763
2583
  * @example
2764
2584
  * ```ts
2765
- * Validation.toMaybe(Validation.passed(42)); // Some(42)
2766
- * Validation.toMaybe(Validation.failed("bad")); // None
2585
+ * const controller = new AbortController();
2586
+ * const result = await pipe(
2587
+ * fetchUser("42"),
2588
+ * TaskResult.chain(user => fetchPosts(user.id)),
2589
+ * TaskResult.run(controller.signal),
2590
+ * );
2591
+ * if (Result.isOk(result)) render(result.value);
2767
2592
  * ```
2768
2593
  */
2769
- const toMaybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
2594
+ const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Promise<Result<E, A>>;
2770
2595
  /**
2771
- * Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
2772
- *
2773
- * Useful when bridging from error-short-circuiting `Result` pipelines into
2774
- * error-accumulating `Validation` pipelines.
2596
+ * Converts a TaskResult value into an object containing a single property.
2597
+ * Initiates the pipeline accumulator record.
2775
2598
  *
2776
2599
  * @example
2777
2600
  * ```ts
2778
- * Validation.fromResult(Result.ok(42)); // Passed(42)
2779
- * Validation.fromResult(Result.err("bad")); // Failed(["bad"])
2601
+ * pipe(TaskResult.ok(42), TaskResult.bindTo("value")); // TaskResult({ value: 42 })
2780
2602
  * ```
2781
2603
  */
2782
- const fromResult: <E, A>(data: Result<E, A>) => Validation<E, A>;
2604
+ const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
2783
2605
  /**
2784
- * Combines two independent Validation instances into a tuple.
2785
- * If both are Passed, returns Passed with both values as a tuple.
2786
- * If either is Failed, accumulates errors from both sides.
2606
+ * Evaluates a new TaskResult using the current accumulator and attaches the output to a new key.
2787
2607
  *
2788
2608
  * @example
2789
2609
  * ```ts
2790
- * Validation.product(
2791
- * Validation.passed("alice"),
2792
- * Validation.passed(30)
2793
- * ); // Passed(["alice", 30])
2794
- *
2795
- * Validation.product(
2796
- * Validation.failed("Name required"),
2797
- * Validation.failed("Age must be >= 0")
2798
- * ); // Failed(["Name required", "Age must be >= 0"])
2610
+ * pipe(
2611
+ * TaskResult.ok({ a: 1 }),
2612
+ * TaskResult.bind("b", ({ a }) => TaskResult.ok(a + 1))
2613
+ * ); // TaskResult({ a: 1, b: 2 })
2799
2614
  * ```
2800
2615
  */
2801
- const product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
2616
+ const bind: <K extends string, E, A, B>(key: K, f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A & { [P in K]: B; }>;
2802
2617
  /**
2803
- * Combines a non-empty list of Validation instances, accumulating all errors.
2804
- * If all are Passed, returns Passed with all values collected into an array.
2805
- * If any are Failed, returns Failed with all accumulated errors.
2618
+ * Combines a record of TaskResults into a single TaskResult of a record.
2619
+ * Evaluates all tasks in parallel, forwarding the AbortSignal down to each sub-task.
2620
+ * Returns the first Err encountered in key order.
2806
2621
  *
2807
2622
  * @example
2808
2623
  * ```ts
2809
- * Validation.productAll([
2810
- * validateName(name),
2811
- * validateEmail(email),
2812
- * validateAge(age)
2813
- * ]);
2814
- * // Passed([name, email, age]) or Failed([...all errors])
2624
+ * TaskResult.struct({
2625
+ * name: TaskResult.ok("Alice"),
2626
+ * age: TaskResult.ok(30)
2627
+ * }); // TaskResult({ name: "Alice", age: 30 })
2815
2628
  * ```
2816
2629
  */
2817
- const productAll: <E, A>(data: NonEmptyList<Validation<E, A>>) => Validation<E, readonly A[]>;
2630
+ const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskResult<E, R[K]>; }) => TaskResult<E, R>;
2818
2631
  }
2819
2632
 
2820
2633
  /**
@@ -3328,4 +3141,329 @@ declare namespace Tuple {
3328
3141
  const tap: <A, B>(f: (a: A, b: B) => void) => (tuple: Tuple<A, B>) => Tuple<A, B>;
3329
3142
  }
3330
3143
 
3144
+ type Passed<A> = WithKind<"Passed"> & WithValue<A>;
3145
+ type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
3146
+ /**
3147
+ * Validation represents a value that is either passed with a success value,
3148
+ * or failed with accumulated errors.
3149
+ * Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
3150
+ *
3151
+ * Use Validation when you need to collect all errors (e.g., form validation).
3152
+ * Use Result when you want to fail fast on the first error.
3153
+ *
3154
+ * @example
3155
+ * ```ts
3156
+ * const validateName = (name: string): Validation<string, string> =>
3157
+ * name.length > 0 ? Validation.passed(name) : Validation.failed("Name is required");
3158
+ *
3159
+ * const validateAge = (age: number): Validation<string, number> =>
3160
+ * age >= 0 ? Validation.passed(age) : Validation.failed("Age must be positive");
3161
+ *
3162
+ * // Accumulates all errors using ap
3163
+ * pipe(
3164
+ * Validation.passed((name: string) => (age: number) => ({ name, age })),
3165
+ * Validation.ap(validateName("")),
3166
+ * Validation.ap(validateAge(-1))
3167
+ * );
3168
+ * // Failed(["Name is required", "Age must be positive"])
3169
+ * ```
3170
+ */
3171
+ type Validation<E, A> = Passed<A> | Failed<E>;
3172
+ declare namespace Validation {
3173
+ /**
3174
+ * Wraps a value in a passed Validation.
3175
+ *
3176
+ * @example
3177
+ * ```ts
3178
+ * Validation.passed(42); // Passed(42)
3179
+ * ```
3180
+ */
3181
+ const passed: <E, A>(value: A) => Validation<E, A>;
3182
+ /**
3183
+ * Creates a failed Validation from a single error.
3184
+ *
3185
+ * @example
3186
+ * ```ts
3187
+ * Validation.failed("Invalid input");
3188
+ * ```
3189
+ */
3190
+ const failed: <E>(error: E) => Failed<E>;
3191
+ /**
3192
+ * Creates a failed Validation from multiple errors.
3193
+ *
3194
+ * @example
3195
+ * ```ts
3196
+ * Validation.failedAll(["Invalid input"]);
3197
+ * ```
3198
+ */
3199
+ const failedAll: <E>(errors: NonEmptyList<E>) => Failed<E>;
3200
+ /**
3201
+ * Type guard that checks if a Validation is passed.
3202
+ */
3203
+ const isPassed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
3204
+ /**
3205
+ * Type guard that checks if a Validation is failed.
3206
+ */
3207
+ const isFailed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
3208
+ /**
3209
+ * Creates a Validation from a predicate applied to a value.
3210
+ * Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
3211
+ *
3212
+ * @example
3213
+ * ```ts
3214
+ * const validateName = Validation.fromPredicate(
3215
+ * (s: string) => s.length > 0,
3216
+ * () => "Name is required"
3217
+ * );
3218
+ *
3219
+ * validateName("Alice"); // Passed("Alice")
3220
+ * validateName(""); // Failed(["Name is required"])
3221
+ * ```
3222
+ */
3223
+ const fromPredicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
3224
+ /**
3225
+ * Creates a Validation from a nullable value.
3226
+ * If the value is null or undefined, returns Failed with the error from onNull.
3227
+ * Otherwise, returns Passed.
3228
+ *
3229
+ * @example
3230
+ * ```ts
3231
+ * pipe(null, Validation.fromNullable(() => "is null")); // Failed(["is null"])
3232
+ * pipe(42, Validation.fromNullable(() => "is null")); // Passed(42)
3233
+ * ```
3234
+ */
3235
+ const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
3236
+ /**
3237
+ * Creates a Validation from a Maybe.
3238
+ * If the Maybe is None, returns Failed with the error from onNone.
3239
+ * Otherwise, returns Passed.
3240
+ *
3241
+ * @example
3242
+ * ```ts
3243
+ * pipe(Maybe.none(), Validation.fromMaybe(() => "is none")); // Failed(["is none"])
3244
+ * pipe(Maybe.some(42), Validation.fromMaybe(() => "is none")); // Passed(42)
3245
+ * ```
3246
+ */
3247
+ const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
3248
+ /**
3249
+ * Transforms the success value inside a Validation.
3250
+ *
3251
+ * @example
3252
+ * ```ts
3253
+ * pipe(Validation.passed(5), Validation.map(n => n * 2)); // Passed(10)
3254
+ * pipe(Validation.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
3255
+ * ```
3256
+ */
3257
+ const map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
3258
+ /**
3259
+ * Transforms the error list inside a Validation.
3260
+ *
3261
+ * @example
3262
+ * ```ts
3263
+ * pipe(Validation.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
3264
+ * ```
3265
+ */
3266
+ const mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
3267
+ /**
3268
+ * Applies a function wrapped in a Validation to a value wrapped in a Validation.
3269
+ * Accumulates errors from both sides.
3270
+ *
3271
+ * @example
3272
+ * ```ts
3273
+ * const add = (a: number) => (b: number) => a + b;
3274
+ * pipe(
3275
+ * Validation.passed(add),
3276
+ * Validation.ap(Validation.passed(5)),
3277
+ * Validation.ap(Validation.passed(3))
3278
+ * ); // Passed(8)
3279
+ *
3280
+ * pipe(
3281
+ * Validation.passed(add),
3282
+ * Validation.ap(Validation.failed<string, number>("bad a")),
3283
+ * Validation.ap(Validation.failed<string, number>("bad b"))
3284
+ * ); // Failed(["bad a", "bad b"])
3285
+ * ```
3286
+ */
3287
+ const ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
3288
+ /**
3289
+ * Extracts the value from a Validation by providing handlers for both cases.
3290
+ *
3291
+ * @example
3292
+ * ```ts
3293
+ * pipe(
3294
+ * Validation.passed(42),
3295
+ * Validation.fold(
3296
+ * errors => `Errors: ${errors.join(", ")}`,
3297
+ * value => `Value: ${value}`
3298
+ * )
3299
+ * );
3300
+ * ```
3301
+ */
3302
+ const fold: <E, A, B>(onFailed: (errors: NonEmptyList<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
3303
+ /**
3304
+ * Pattern matches on a Validation, returning the result of the matching case.
3305
+ *
3306
+ * @example
3307
+ * ```ts
3308
+ * pipe(
3309
+ * validation,
3310
+ * Validation.match({
3311
+ * passed: value => `Got ${value}`,
3312
+ * failed: errors => `Failed: ${errors.join(", ")}`
3313
+ * })
3314
+ * );
3315
+ * ```
3316
+ */
3317
+ const match: <E, A, B>(cases: {
3318
+ passed: (a: A) => B;
3319
+ failed: (errors: NonEmptyList<E>) => B;
3320
+ }) => (data: Validation<E, A>) => B;
3321
+ /**
3322
+ * Returns the success value or a default value if the Validation is failed.
3323
+ * The default can be a different type, widening the result to `A | B`.
3324
+ *
3325
+ * @example
3326
+ * ```ts
3327
+ * pipe(Validation.passed(5), Validation.getOrElse(() => 0)); // 5
3328
+ * pipe(Validation.failed("oops"), Validation.getOrElse(() => 0)); // 0
3329
+ * pipe(Validation.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
3330
+ * ```
3331
+ */
3332
+ const getOrElse: <E, A, B>(defaultValue: () => B) => (data: Validation<E, A>) => A | B;
3333
+ /**
3334
+ * Executes a side effect on the success value without changing the Validation.
3335
+ *
3336
+ * @example
3337
+ * ```ts
3338
+ * pipe(
3339
+ * Validation.passed(5),
3340
+ * Validation.tap(n => console.log("Value:", n)),
3341
+ * Validation.map(n => n * 2)
3342
+ * );
3343
+ * ```
3344
+ */
3345
+ const tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
3346
+ /**
3347
+ * Executes a side effect on the accumulated errors without changing the Validation.
3348
+ * Useful for logging or reporting validation failures.
3349
+ *
3350
+ * @example
3351
+ * ```ts
3352
+ * pipe(
3353
+ * Validation.failed("Name required"),
3354
+ * Validation.tapError(errors => console.error("validation failed:", errors)),
3355
+ * Validation.map(toUser)
3356
+ * );
3357
+ * ```
3358
+ */
3359
+ const tapError: <E, A>(f: (errors: NonEmptyList<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
3360
+ /**
3361
+ * Recovers from a Failed state by providing a fallback Validation.
3362
+ * The fallback receives the accumulated error list so callers can inspect which errors occurred.
3363
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
3364
+ */
3365
+ const recover: <E, A, B>(fallback: (errors: NonEmptyList<E>) => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
3366
+ /**
3367
+ * Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
3368
+ * The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
3369
+ *
3370
+ * @example
3371
+ * ```ts
3372
+ * pipe(
3373
+ * Validation.failed("field-error"),
3374
+ * Validation.recoverUnless(e => e === "fatal", () => Validation.passed(0))
3375
+ * ); // Passed(0)
3376
+ * ```
3377
+ */
3378
+ const recoverUnless: <E, A, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
3379
+ /**
3380
+ * Converts a Validation to a Result.
3381
+ * Passed becomes Ok, Failed becomes Err with the accumulated error list.
3382
+ *
3383
+ * @example
3384
+ * ```ts
3385
+ * Validation.toResult(Validation.passed(42)); // Ok(42)
3386
+ * Validation.toResult(Validation.failed("oops")); // Err(["oops"])
3387
+ * ```
3388
+ */
3389
+ const toResult: <E, A>(data: Validation<E, A>) => Result<NonEmptyList<E>, A>;
3390
+ /**
3391
+ * Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
3392
+ * (errors are discarded).
3393
+ *
3394
+ * @example
3395
+ * ```ts
3396
+ * Validation.toMaybe(Validation.passed(42)); // Some(42)
3397
+ * Validation.toMaybe(Validation.failed("bad")); // None
3398
+ * ```
3399
+ */
3400
+ const toMaybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
3401
+ /**
3402
+ * Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
3403
+ *
3404
+ * Useful when bridging from error-short-circuiting `Result` pipelines into
3405
+ * error-accumulating `Validation` pipelines.
3406
+ *
3407
+ * @example
3408
+ * ```ts
3409
+ * Validation.fromResult(Result.ok(42)); // Passed(42)
3410
+ * Validation.fromResult(Result.err("bad")); // Failed(["bad"])
3411
+ * ```
3412
+ */
3413
+ const fromResult: <E, A>(data: Result<E, A>) => Validation<E, A>;
3414
+ /**
3415
+ * Combines two independent Validation instances into a tuple.
3416
+ * If both are Passed, returns Passed with both values as a tuple.
3417
+ * If either is Failed, accumulates errors from both sides.
3418
+ *
3419
+ * @example
3420
+ * ```ts
3421
+ * Validation.product(
3422
+ * Validation.passed("alice"),
3423
+ * Validation.passed(30)
3424
+ * ); // Passed(["alice", 30])
3425
+ *
3426
+ * Validation.product(
3427
+ * Validation.failed("Name required"),
3428
+ * Validation.failed("Age must be >= 0")
3429
+ * ); // Failed(["Name required", "Age must be >= 0"])
3430
+ * ```
3431
+ */
3432
+ const product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
3433
+ /**
3434
+ * Combines a non-empty list of Validation instances, accumulating all errors.
3435
+ * If all are Passed, returns Passed with all values collected into an array.
3436
+ * If any are Failed, returns Failed with all accumulated errors.
3437
+ *
3438
+ * @example
3439
+ * ```ts
3440
+ * Validation.productAll([
3441
+ * validateName(name),
3442
+ * validateEmail(email),
3443
+ * validateAge(age)
3444
+ * ]);
3445
+ * // Passed([name, email, age]) or Failed([...all errors])
3446
+ * ```
3447
+ */
3448
+ const productAll: <E, A>(data: NonEmptyList<Validation<E, A>>) => Validation<E, readonly A[]>;
3449
+ /**
3450
+ * Combines a record of Validations into a single Validation of a record.
3451
+ * Accumulates all failed branches' errors.
3452
+ *
3453
+ * @example
3454
+ * ```ts
3455
+ * Validation.struct({
3456
+ * name: Validation.passed("Alice"),
3457
+ * age: Validation.passed(30)
3458
+ * }); // Passed({ name: "Alice", age: 30 })
3459
+ *
3460
+ * Validation.struct({
3461
+ * name: Validation.failed("Name required"),
3462
+ * age: Validation.failed("Age must be >= 0")
3463
+ * }); // Failed(["Name required", "Age must be >= 0"])
3464
+ * ```
3465
+ */
3466
+ const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Validation<E, R[K]>; }) => Validation<E, R>;
3467
+ }
3468
+
3331
3469
  export { Combinable, Deferred, type Failed, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, type Passed, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, type Success, Task, TaskMaybe, TaskResult, TaskValidation, These, type TheseBoth, type TheseFirst, type TheseSecond, Tuple, Validation };