@nlozgachev/pipelined 0.37.0 → 0.38.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 +18 -7
- package/dist/{Task-fn1n--6H.d.mts → Task-DcXhCZYg.d.mts} +429 -403
- package/dist/{Task-DIgwvoIb.d.ts → Task-uupX7xd9.d.ts} +429 -403
- package/dist/{chunk-VWVPHDZO.mjs → chunk-5AFEEFE4.mjs} +5 -1
- package/dist/{chunk-72BGUEQM.mjs → chunk-E7YI5PVW.mjs} +2 -2
- package/dist/{chunk-SHO53CQC.mjs → chunk-M2X7TFKN.mjs} +483 -103
- package/dist/core.d.mts +683 -651
- package/dist/core.d.ts +683 -651
- package/dist/core.js +319 -261
- package/dist/core.mjs +6 -8
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +336 -278
- package/dist/index.mjs +16 -21
- package/dist/types.d.mts +29 -29
- package/dist/types.d.ts +29 -29
- package/dist/types.mjs +3 -6
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +81 -55
- package/dist/utils.mjs +3 -4
- package/package.json +10 -3
- package/dist/chunk-DBIC62UV.mjs +0 -6
- package/dist/chunk-IPP4XFYH.mjs +0 -0
- package/dist/chunk-PUMSVZB4.mjs +0 -334
package/dist/core.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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,
|
|
2
|
-
export { E as Equality, a as Err, N as None, O as Ok, b as Ordering, S as Some } from './Task-
|
|
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-DcXhCZYg.mjs';
|
|
2
|
+
export { E as Equality, a as Err, N as None, O as Ok, b as Ordering, S as Some } from './Task-DcXhCZYg.mjs';
|
|
3
3
|
import { Duration, NonEmptyList } from './types.mjs';
|
|
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.
|
|
@@ -1286,140 +1131,159 @@ declare namespace Op {
|
|
|
1286
1131
|
function interpret<I, E, A, O extends AllInterpretOptions<I, E>>(op: Op<I, E, A>, options: O): InterpretResult<I, E, A, O>;
|
|
1287
1132
|
}
|
|
1288
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];
|
|
1289
1138
|
/**
|
|
1290
|
-
* A
|
|
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>.
|
|
1291
1141
|
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
* express domain invariants (non-empty strings, positive numbers, valid emails) as
|
|
1295
|
-
* first-class, composable values rather than one-off type guards scattered across
|
|
1296
|
-
* 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`.
|
|
1297
1144
|
*
|
|
1298
1145
|
* @example
|
|
1299
1146
|
* ```ts
|
|
1300
|
-
* type
|
|
1147
|
+
* type Profile = { username: string; bio?: string };
|
|
1301
1148
|
*
|
|
1302
|
-
* const
|
|
1303
|
-
* Refinement.make(s => s.length > 0);
|
|
1149
|
+
* const bioOpt = Optional.prop<Profile>()("bio");
|
|
1304
1150
|
*
|
|
1305
|
-
* pipe(
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
* ); // 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
|
|
1309
1154
|
* ```
|
|
1310
1155
|
*/
|
|
1311
|
-
type
|
|
1312
|
-
|
|
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 {
|
|
1313
1161
|
/**
|
|
1314
|
-
*
|
|
1315
|
-
*
|
|
1316
|
-
* This is an unsafe cast — the caller is responsible for ensuring that the
|
|
1317
|
-
* predicate truly characterises values of type `B`. Use this only when
|
|
1318
|
-
* bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
|
|
1319
|
-
* derived refinements from existing ones.
|
|
1162
|
+
* Constructs an Optional from a getter (returning Maybe<A>) and a setter.
|
|
1320
1163
|
*
|
|
1321
1164
|
* @example
|
|
1322
1165
|
* ```ts
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
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
|
+
* );
|
|
1327
1170
|
* ```
|
|
1328
1171
|
*/
|
|
1329
|
-
const make: <
|
|
1172
|
+
const make: <S, A>(get: (s: S) => Maybe<A>, set: (a: A) => (s: S) => S) => Optional<S, A>;
|
|
1330
1173
|
/**
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
*
|
|
1334
|
-
* 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.
|
|
1335
1177
|
*
|
|
1336
1178
|
* @example
|
|
1337
1179
|
* ```ts
|
|
1338
|
-
* type
|
|
1339
|
-
*
|
|
1340
|
-
*
|
|
1341
|
-
* const isNonEmpty: Refinement<string, NonEmptyString> =
|
|
1342
|
-
* Refinement.make(s => s.length > 0);
|
|
1343
|
-
* const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
|
|
1344
|
-
* Refinement.make(s => s === s.trim());
|
|
1345
|
-
*
|
|
1346
|
-
* const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
|
|
1347
|
-
* isNonEmpty,
|
|
1348
|
-
* Refinement.compose(isTrimmed)
|
|
1349
|
-
* );
|
|
1180
|
+
* type Profile = { username: string; bio?: string };
|
|
1181
|
+
* const bioOpt = Optional.prop<Profile>()("bio");
|
|
1350
1182
|
* ```
|
|
1351
1183
|
*/
|
|
1352
|
-
const
|
|
1184
|
+
const prop: <S>() => <K extends OptionalKeys<S>>(key: K) => Optional<S, NonNullable<S[K]>>;
|
|
1353
1185
|
/**
|
|
1354
|
-
*
|
|
1355
|
-
* when
|
|
1356
|
-
*
|
|
1357
|
-
* 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.
|
|
1358
1188
|
*
|
|
1359
1189
|
* @example
|
|
1360
1190
|
* ```ts
|
|
1361
|
-
* const
|
|
1362
|
-
* const isNonEmpty: Refinement<unknown, { length: number }> =
|
|
1363
|
-
* Refinement.make(x => (x as any).length > 0);
|
|
1191
|
+
* const firstItem = Optional.index<string>(0);
|
|
1364
1192
|
*
|
|
1365
|
-
*
|
|
1366
|
-
*
|
|
1367
|
-
* isNonEmptyString(""); // false
|
|
1193
|
+
* pipe(["a", "b"], Optional.get(firstItem)); // Some("a")
|
|
1194
|
+
* pipe([], Optional.get(firstItem)); // None
|
|
1368
1195
|
* ```
|
|
1369
1196
|
*/
|
|
1370
|
-
const
|
|
1197
|
+
const index: <A>(i: number) => Optional<A[], A>;
|
|
1371
1198
|
/**
|
|
1372
|
-
*
|
|
1373
|
-
* refinement holds.
|
|
1374
|
-
*
|
|
1375
|
-
* Data-last — the first refinement is the data being piped.
|
|
1199
|
+
* Reads the focused value from a structure, returning Maybe<A>.
|
|
1376
1200
|
*
|
|
1377
1201
|
* @example
|
|
1378
1202
|
* ```ts
|
|
1379
|
-
*
|
|
1380
|
-
* const isNumber: Refinement<unknown, number> = Refinement.make(x => typeof x === "number");
|
|
1381
|
-
*
|
|
1382
|
-
* const isStringOrNumber = pipe(isString, Refinement.or(isNumber));
|
|
1383
|
-
* isStringOrNumber("hi"); // true
|
|
1384
|
-
* isStringOrNumber(42); // true
|
|
1385
|
-
* isStringOrNumber(true); // false
|
|
1203
|
+
* pipe(profile, Optional.get(bioOpt)); // Some("...") or None
|
|
1386
1204
|
* ```
|
|
1387
1205
|
*/
|
|
1388
|
-
const
|
|
1206
|
+
const get: <S, A>(opt: Optional<S, A>) => (s: S) => Maybe<A>;
|
|
1389
1207
|
/**
|
|
1390
|
-
*
|
|
1208
|
+
* Replaces the focused value within a structure.
|
|
1209
|
+
* For indexed focuses, this is a no-op when the index is out of bounds.
|
|
1391
1210
|
*
|
|
1392
|
-
*
|
|
1393
|
-
*
|
|
1211
|
+
* @example
|
|
1212
|
+
* ```ts
|
|
1213
|
+
* pipe(profile, Optional.set(bioOpt)("hello"));
|
|
1214
|
+
* ```
|
|
1215
|
+
*/
|
|
1216
|
+
const set: <S, A>(opt: Optional<S, A>) => (a: A) => (s: S) => S;
|
|
1217
|
+
/**
|
|
1218
|
+
* Applies a function to the focused value if it is present; returns the
|
|
1219
|
+
* structure unchanged if the focus is absent.
|
|
1394
1220
|
*
|
|
1395
1221
|
* @example
|
|
1396
1222
|
* ```ts
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1399
|
-
|
|
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.
|
|
1400
1229
|
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1230
|
+
* @example
|
|
1231
|
+
* ```ts
|
|
1232
|
+
* pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
|
|
1403
1233
|
* ```
|
|
1404
1234
|
*/
|
|
1405
|
-
const
|
|
1235
|
+
const getOrElse: <S, A>(opt: Optional<S, A>) => (defaultValue: () => A) => (s: S) => A;
|
|
1406
1236
|
/**
|
|
1407
|
-
*
|
|
1237
|
+
* Extracts a value from an Optional focus using handlers for the present
|
|
1238
|
+
* and absent cases.
|
|
1408
1239
|
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1240
|
+
* @example
|
|
1241
|
+
* ```ts
|
|
1242
|
+
* pipe(profile, Optional.fold(bioOpt)(() => "no bio", (bio) => bio.toUpperCase()));
|
|
1243
|
+
* ```
|
|
1244
|
+
*/
|
|
1245
|
+
const fold: <S, A>(opt: Optional<S, A>) => <B>(onNone: () => B, onSome: (a: A) => B) => (s: S) => B;
|
|
1246
|
+
/**
|
|
1247
|
+
* Pattern matches on an Optional focus using a named-case object.
|
|
1411
1248
|
*
|
|
1412
1249
|
* @example
|
|
1413
1250
|
* ```ts
|
|
1414
|
-
*
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
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.
|
|
1417
1264
|
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1265
|
+
* @example
|
|
1266
|
+
* ```ts
|
|
1267
|
+
* const deepOpt = pipe(
|
|
1268
|
+
* Optional.prop<User>()("address"),
|
|
1269
|
+
* Optional.andThen(Optional.prop<Address>()("landmark")),
|
|
1270
|
+
* );
|
|
1420
1271
|
* ```
|
|
1421
1272
|
*/
|
|
1422
|
-
const
|
|
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.
|
|
1277
|
+
*
|
|
1278
|
+
* @example
|
|
1279
|
+
* ```ts
|
|
1280
|
+
* const cityOpt = pipe(
|
|
1281
|
+
* Optional.prop<User>()("address"),
|
|
1282
|
+
* Optional.andThenLens(Lens.prop<Address>()("city")),
|
|
1283
|
+
* );
|
|
1284
|
+
* ```
|
|
1285
|
+
*/
|
|
1286
|
+
const andThenLens: <A, B>(inner: Lens<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
|
|
1423
1287
|
}
|
|
1424
1288
|
|
|
1425
1289
|
/**
|
|
@@ -1759,6 +1623,142 @@ declare namespace Reader {
|
|
|
1759
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; }>;
|
|
1760
1624
|
}
|
|
1761
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>;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
1762
|
type NotAsked = WithKind<"NotAsked">;
|
|
1763
1763
|
type Loading = WithKind<"Loading">;
|
|
1764
1764
|
type Failure<E> = WithKind<"Failure"> & WithError<E>;
|
|
@@ -2004,186 +2004,31 @@ declare namespace RemoteData {
|
|
|
2004
2004
|
}
|
|
2005
2005
|
|
|
2006
2006
|
/**
|
|
2007
|
-
* A
|
|
2008
|
-
*
|
|
2007
|
+
* A Resource pairs an async acquisition step with a guaranteed cleanup step.
|
|
2008
|
+
*
|
|
2009
|
+
* Use it whenever something must be explicitly closed, released, or torn down
|
|
2010
|
+
* after you are done with it — database connections, file handles, locks,
|
|
2011
|
+
* temporary directories, or any object with a lifecycle.
|
|
2012
|
+
*
|
|
2013
|
+
* The key guarantee: `release` always runs after `Resource.use`, even when
|
|
2014
|
+
* the work function returns an error. If `acquire` itself fails, `release` is
|
|
2015
|
+
* skipped — there is nothing to clean up.
|
|
2016
|
+
*
|
|
2017
|
+
* Build a Resource with `Resource.make` or `Resource.fromTask`, then run it
|
|
2018
|
+
* with `Resource.use`.
|
|
2009
2019
|
*
|
|
2010
2020
|
* @example
|
|
2011
2021
|
* ```ts
|
|
2012
|
-
* const
|
|
2013
|
-
* TaskResult.tryCatch(
|
|
2014
|
-
*
|
|
2015
|
-
*
|
|
2016
|
-
*
|
|
2017
|
-
*
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
* Wraps a value in a successful TaskResult.
|
|
2023
|
-
*/
|
|
2024
|
-
const ok: <E, A>(value: A) => TaskResult<E, A>;
|
|
2025
|
-
/**
|
|
2026
|
-
* Creates a failed TaskResult with the given error.
|
|
2027
|
-
*/
|
|
2028
|
-
const err: <E, A>(error: E) => TaskResult<E, A>;
|
|
2029
|
-
/**
|
|
2030
|
-
* Creates a TaskResult from a nullable value.
|
|
2031
|
-
* Returns Ok if the value is not null or undefined, err from onNull otherwise.
|
|
2032
|
-
*/
|
|
2033
|
-
const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
|
|
2034
|
-
/**
|
|
2035
|
-
* Creates a TaskResult from a Maybe.
|
|
2036
|
-
* Some becomes Ok, None becomes err from onNone.
|
|
2037
|
-
*/
|
|
2038
|
-
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
|
|
2039
|
-
/**
|
|
2040
|
-
* Lifts a Result into a TaskResult.
|
|
2041
|
-
*/
|
|
2042
|
-
const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
|
|
2043
|
-
/**
|
|
2044
|
-
* Wraps a Promise-returning function of any arguments, returning a new function
|
|
2045
|
-
* that catches rejections and returns a TaskResult.
|
|
2046
|
-
*/
|
|
2047
|
-
const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => Promise<A>, onError: (e: unknown) => E) => (...args: Args) => TaskResult<E, A>;
|
|
2048
|
-
/**
|
|
2049
|
-
* Creates a TaskResult from a function that may throw.
|
|
2050
|
-
* Catches any errors and transforms them using the onError function.
|
|
2051
|
-
* The factory optionally receives an `AbortSignal` forwarded from the call site.
|
|
2052
|
-
*
|
|
2053
|
-
* @example
|
|
2054
|
-
* ```ts
|
|
2055
|
-
* const fetchUser = (id: string): TaskResult<string, User> =>
|
|
2056
|
-
* TaskResult.tryCatch(
|
|
2057
|
-
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
2058
|
-
* String
|
|
2059
|
-
* );
|
|
2060
|
-
* ```
|
|
2061
|
-
*/
|
|
2062
|
-
const tryCatch: <E, A>(f: (signal?: AbortSignal) => Promise<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
|
|
2063
|
-
/**
|
|
2064
|
-
* Transforms the success value inside a TaskResult.
|
|
2065
|
-
*/
|
|
2066
|
-
const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2067
|
-
/**
|
|
2068
|
-
* Transforms the error value inside a TaskResult.
|
|
2069
|
-
*/
|
|
2070
|
-
const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
|
|
2071
|
-
/**
|
|
2072
|
-
* Chains TaskResult computations. If the first succeeds, passes the value to f.
|
|
2073
|
-
* If the first fails, propagates the error.
|
|
2074
|
-
*/
|
|
2075
|
-
const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2076
|
-
/**
|
|
2077
|
-
* Extracts the value from a TaskResult by providing handlers for both cases.
|
|
2078
|
-
*/
|
|
2079
|
-
const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
|
|
2080
|
-
/**
|
|
2081
|
-
* Pattern matches on a TaskResult, returning a Task of the result.
|
|
2082
|
-
*/
|
|
2083
|
-
const match: <E, A, B>(cases: {
|
|
2084
|
-
err: (e: E) => B;
|
|
2085
|
-
ok: (a: A) => B;
|
|
2086
|
-
}) => (data: TaskResult<E, A>) => Task<B>;
|
|
2087
|
-
/**
|
|
2088
|
-
* Recovers from an error by providing a fallback TaskResult.
|
|
2089
|
-
* The fallback can produce a different success type, widening the result to `TaskResult<E, A | B>`.
|
|
2090
|
-
*/
|
|
2091
|
-
const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
|
|
2092
|
-
/**
|
|
2093
|
-
* Returns the success value or a default value if the TaskResult is an error.
|
|
2094
|
-
* The default can be a different type, widening the result to `Task<A | B>`.
|
|
2095
|
-
*/
|
|
2096
|
-
const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
|
|
2097
|
-
/**
|
|
2098
|
-
* Executes a side effect on the success value without changing the TaskResult.
|
|
2099
|
-
* Useful for logging or debugging.
|
|
2100
|
-
*/
|
|
2101
|
-
const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2102
|
-
/**
|
|
2103
|
-
* Executes a side effect on the error value without changing the TaskResult.
|
|
2104
|
-
* Useful for logging or reporting async errors.
|
|
2105
|
-
*
|
|
2106
|
-
* @example
|
|
2107
|
-
* ```ts
|
|
2108
|
-
* pipe(
|
|
2109
|
-
* fetchUser(id),
|
|
2110
|
-
* TaskResult.tapError(e => console.error("fetch failed:", e)),
|
|
2111
|
-
* TaskResult.chain(saveToCache),
|
|
2112
|
-
* )
|
|
2113
|
-
* ```
|
|
2114
|
-
*/
|
|
2115
|
-
const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2116
|
-
/**
|
|
2117
|
-
* Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
|
|
2118
|
-
* Both Tasks run in parallel.
|
|
2119
|
-
*/
|
|
2120
|
-
const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
|
|
2121
|
-
/**
|
|
2122
|
-
* Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
|
|
2123
|
-
* Use as a terminal step in a `pipe` chain.
|
|
2124
|
-
*
|
|
2125
|
-
* @example
|
|
2126
|
-
* ```ts
|
|
2127
|
-
* const controller = new AbortController();
|
|
2128
|
-
* const result = await pipe(
|
|
2129
|
-
* fetchUser("42"),
|
|
2130
|
-
* TaskResult.chain(user => fetchPosts(user.id)),
|
|
2131
|
-
* TaskResult.run(controller.signal),
|
|
2132
|
-
* );
|
|
2133
|
-
* if (Result.isOk(result)) render(result.value);
|
|
2134
|
-
* ```
|
|
2135
|
-
*/
|
|
2136
|
-
const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Promise<Result<E, A>>;
|
|
2137
|
-
/**
|
|
2138
|
-
* Converts a TaskResult value into an object containing a single property.
|
|
2139
|
-
* Initiates the pipeline accumulator record.
|
|
2140
|
-
*
|
|
2141
|
-
* @example
|
|
2142
|
-
* ```ts
|
|
2143
|
-
* pipe(TaskResult.ok(42), TaskResult.bindTo("value")); // TaskResult({ value: 42 })
|
|
2144
|
-
* ```
|
|
2145
|
-
*/
|
|
2146
|
-
const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
|
|
2147
|
-
/**
|
|
2148
|
-
* Evaluates a new TaskResult using the current accumulator and attaches the output to a new key.
|
|
2149
|
-
*
|
|
2150
|
-
* @example
|
|
2151
|
-
* ```ts
|
|
2152
|
-
* pipe(
|
|
2153
|
-
* TaskResult.ok({ a: 1 }),
|
|
2154
|
-
* TaskResult.bind("b", ({ a }) => TaskResult.ok(a + 1))
|
|
2155
|
-
* ); // TaskResult({ a: 1, b: 2 })
|
|
2156
|
-
* ```
|
|
2157
|
-
*/
|
|
2158
|
-
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; }>;
|
|
2159
|
-
}
|
|
2160
|
-
|
|
2161
|
-
/**
|
|
2162
|
-
* A Resource pairs an async acquisition step with a guaranteed cleanup step.
|
|
2163
|
-
*
|
|
2164
|
-
* Use it whenever something must be explicitly closed, released, or torn down
|
|
2165
|
-
* after you are done with it — database connections, file handles, locks,
|
|
2166
|
-
* temporary directories, or any object with a lifecycle.
|
|
2167
|
-
*
|
|
2168
|
-
* The key guarantee: `release` always runs after `Resource.use`, even when
|
|
2169
|
-
* the work function returns an error. If `acquire` itself fails, `release` is
|
|
2170
|
-
* skipped — there is nothing to clean up.
|
|
2171
|
-
*
|
|
2172
|
-
* Build a Resource with `Resource.make` or `Resource.fromTask`, then run it
|
|
2173
|
-
* with `Resource.use`.
|
|
2174
|
-
*
|
|
2175
|
-
* @example
|
|
2176
|
-
* ```ts
|
|
2177
|
-
* const dbResource = Resource.make(
|
|
2178
|
-
* TaskResult.tryCatch(() => openConnection(config), (e) => new DbError(e)),
|
|
2179
|
-
* (conn) => Task.from(() => conn.close())
|
|
2180
|
-
* );
|
|
2181
|
-
*
|
|
2182
|
-
* const result = await pipe(
|
|
2183
|
-
* dbResource,
|
|
2184
|
-
* Resource.use((conn) => queryUser(conn, userId))
|
|
2185
|
-
* )();
|
|
2186
|
-
* // conn.close() is called whether queryUser succeeds or fails
|
|
2022
|
+
* const dbResource = Resource.make(
|
|
2023
|
+
* TaskResult.tryCatch(() => openConnection(config), (e) => new DbError(e)),
|
|
2024
|
+
* (conn) => Task.from(() => conn.close())
|
|
2025
|
+
* );
|
|
2026
|
+
*
|
|
2027
|
+
* const result = await pipe(
|
|
2028
|
+
* dbResource,
|
|
2029
|
+
* Resource.use((conn) => queryUser(conn, userId))
|
|
2030
|
+
* )();
|
|
2031
|
+
* // conn.close() is called whether queryUser succeeds or fails
|
|
2187
2032
|
* ```
|
|
2188
2033
|
*/
|
|
2189
2034
|
type Resource<E, A> = {
|
|
@@ -2616,311 +2461,173 @@ declare namespace TaskMaybe {
|
|
|
2616
2461
|
const bind: <K extends string, A, B>(key: K, f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<A & { [P in K]: B; }>;
|
|
2617
2462
|
}
|
|
2618
2463
|
|
|
2619
|
-
type Passed<A> = WithKind<"Passed"> & WithValue<A>;
|
|
2620
|
-
type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
|
|
2621
2464
|
/**
|
|
2622
|
-
*
|
|
2623
|
-
*
|
|
2624
|
-
* Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
|
|
2625
|
-
*
|
|
2626
|
-
* Use Validation when you need to collect all errors (e.g., form validation).
|
|
2627
|
-
* Use Result when you want to fail fast on the first error.
|
|
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.
|
|
2628
2467
|
*
|
|
2629
2468
|
* @example
|
|
2630
2469
|
* ```ts
|
|
2631
|
-
* const
|
|
2632
|
-
*
|
|
2633
|
-
*
|
|
2634
|
-
*
|
|
2635
|
-
*
|
|
2636
|
-
*
|
|
2637
|
-
* // Accumulates all errors using ap
|
|
2638
|
-
* pipe(
|
|
2639
|
-
* Validation.passed((name: string) => (age: number) => ({ name, age })),
|
|
2640
|
-
* Validation.ap(validateName("")),
|
|
2641
|
-
* Validation.ap(validateAge(-1))
|
|
2642
|
-
* );
|
|
2643
|
-
* // Failed(["Name is required", "Age must be positive"])
|
|
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
|
+
* );
|
|
2644
2475
|
* ```
|
|
2645
2476
|
*/
|
|
2646
|
-
type
|
|
2647
|
-
declare namespace
|
|
2477
|
+
type TaskResult<E, A> = Task<Result<E, A>>;
|
|
2478
|
+
declare namespace TaskResult {
|
|
2648
2479
|
/**
|
|
2649
|
-
* Wraps a value in a
|
|
2650
|
-
*
|
|
2651
|
-
* @example
|
|
2652
|
-
* ```ts
|
|
2653
|
-
* Validation.passed(42); // Passed(42)
|
|
2654
|
-
* ```
|
|
2480
|
+
* Wraps a value in a successful TaskResult.
|
|
2655
2481
|
*/
|
|
2656
|
-
const
|
|
2482
|
+
const ok: <E, A>(value: A) => TaskResult<E, A>;
|
|
2657
2483
|
/**
|
|
2658
|
-
* Creates a failed
|
|
2659
|
-
*
|
|
2660
|
-
* @example
|
|
2661
|
-
* ```ts
|
|
2662
|
-
* Validation.failed("Invalid input");
|
|
2663
|
-
* ```
|
|
2484
|
+
* Creates a failed TaskResult with the given error.
|
|
2664
2485
|
*/
|
|
2665
|
-
const
|
|
2486
|
+
const err: <E, A>(error: E) => TaskResult<E, A>;
|
|
2666
2487
|
/**
|
|
2667
|
-
* Creates a
|
|
2668
|
-
*
|
|
2669
|
-
* @example
|
|
2670
|
-
* ```ts
|
|
2671
|
-
* Validation.failedAll(["Invalid input"]);
|
|
2672
|
-
* ```
|
|
2488
|
+
* Creates a TaskResult from a nullable value.
|
|
2489
|
+
* Returns Ok if the value is not null or undefined, err from onNull otherwise.
|
|
2673
2490
|
*/
|
|
2674
|
-
const
|
|
2491
|
+
const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
|
|
2675
2492
|
/**
|
|
2676
|
-
*
|
|
2493
|
+
* Creates a TaskResult from a Maybe.
|
|
2494
|
+
* Some becomes Ok, None becomes err from onNone.
|
|
2677
2495
|
*/
|
|
2678
|
-
const
|
|
2496
|
+
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
|
|
2679
2497
|
/**
|
|
2680
|
-
*
|
|
2498
|
+
* Lifts a Result into a TaskResult.
|
|
2681
2499
|
*/
|
|
2682
|
-
const
|
|
2500
|
+
const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
|
|
2683
2501
|
/**
|
|
2684
|
-
*
|
|
2685
|
-
*
|
|
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.
|
|
2686
2510
|
*
|
|
2687
2511
|
* @example
|
|
2688
2512
|
* ```ts
|
|
2689
|
-
* const
|
|
2690
|
-
* (
|
|
2691
|
-
*
|
|
2692
|
-
*
|
|
2693
|
-
*
|
|
2694
|
-
* validateName("Alice"); // Passed("Alice")
|
|
2695
|
-
* validateName(""); // Failed(["Name is required"])
|
|
2513
|
+
* const fetchUser = (id: string): TaskResult<string, User> =>
|
|
2514
|
+
* TaskResult.tryCatch(
|
|
2515
|
+
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
2516
|
+
* String
|
|
2517
|
+
* );
|
|
2696
2518
|
* ```
|
|
2697
2519
|
*/
|
|
2698
|
-
const
|
|
2699
|
-
/**
|
|
2700
|
-
* Creates a Validation from a nullable value.
|
|
2701
|
-
* If the value is null or undefined, returns Failed with the error from onNull.
|
|
2702
|
-
* Otherwise, returns Passed.
|
|
2703
|
-
*
|
|
2704
|
-
* @example
|
|
2705
|
-
* ```ts
|
|
2706
|
-
* pipe(null, Validation.fromNullable(() => "is null")); // Failed(["is null"])
|
|
2707
|
-
* pipe(42, Validation.fromNullable(() => "is null")); // Passed(42)
|
|
2708
|
-
* ```
|
|
2709
|
-
*/
|
|
2710
|
-
const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
|
|
2711
|
-
/**
|
|
2712
|
-
* Creates a Validation from a Maybe.
|
|
2713
|
-
* If the Maybe is None, returns Failed with the error from onNone.
|
|
2714
|
-
* Otherwise, returns Passed.
|
|
2715
|
-
*
|
|
2716
|
-
* @example
|
|
2717
|
-
* ```ts
|
|
2718
|
-
* pipe(Maybe.none(), Validation.fromMaybe(() => "is none")); // Failed(["is none"])
|
|
2719
|
-
* pipe(Maybe.some(42), Validation.fromMaybe(() => "is none")); // Passed(42)
|
|
2720
|
-
* ```
|
|
2721
|
-
*/
|
|
2722
|
-
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
|
|
2520
|
+
const tryCatch: <E, A>(f: (signal?: AbortSignal) => Promise<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
|
|
2723
2521
|
/**
|
|
2724
|
-
* Transforms the success value inside a
|
|
2725
|
-
*
|
|
2726
|
-
* @example
|
|
2727
|
-
* ```ts
|
|
2728
|
-
* pipe(Validation.passed(5), Validation.map(n => n * 2)); // Passed(10)
|
|
2729
|
-
* pipe(Validation.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
|
|
2730
|
-
* ```
|
|
2522
|
+
* Transforms the success value inside a TaskResult.
|
|
2731
2523
|
*/
|
|
2732
|
-
const map: <A, B>(f: (a: A) => B) =>
|
|
2524
|
+
const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2733
2525
|
/**
|
|
2734
|
-
* Transforms the error
|
|
2735
|
-
*
|
|
2736
|
-
* @example
|
|
2737
|
-
* ```ts
|
|
2738
|
-
* pipe(Validation.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
|
|
2739
|
-
* ```
|
|
2526
|
+
* Transforms the error value inside a TaskResult.
|
|
2740
2527
|
*/
|
|
2741
|
-
const mapError: <E, F, A>(f: (e: E) => F) => (data:
|
|
2528
|
+
const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
|
|
2742
2529
|
/**
|
|
2743
|
-
*
|
|
2744
|
-
*
|
|
2745
|
-
*
|
|
2746
|
-
* @example
|
|
2747
|
-
* ```ts
|
|
2748
|
-
* const add = (a: number) => (b: number) => a + b;
|
|
2749
|
-
* pipe(
|
|
2750
|
-
* Validation.passed(add),
|
|
2751
|
-
* Validation.ap(Validation.passed(5)),
|
|
2752
|
-
* Validation.ap(Validation.passed(3))
|
|
2753
|
-
* ); // Passed(8)
|
|
2754
|
-
*
|
|
2755
|
-
* pipe(
|
|
2756
|
-
* Validation.passed(add),
|
|
2757
|
-
* Validation.ap(Validation.failed<string, number>("bad a")),
|
|
2758
|
-
* Validation.ap(Validation.failed<string, number>("bad b"))
|
|
2759
|
-
* ); // Failed(["bad a", "bad b"])
|
|
2760
|
-
* ```
|
|
2530
|
+
* Chains TaskResult computations. If the first succeeds, passes the value to f.
|
|
2531
|
+
* If the first fails, propagates the error.
|
|
2761
2532
|
*/
|
|
2762
|
-
const
|
|
2533
|
+
const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2763
2534
|
/**
|
|
2764
|
-
* Extracts the value from a
|
|
2765
|
-
*
|
|
2766
|
-
* @example
|
|
2767
|
-
* ```ts
|
|
2768
|
-
* pipe(
|
|
2769
|
-
* Validation.passed(42),
|
|
2770
|
-
* Validation.fold(
|
|
2771
|
-
* errors => `Errors: ${errors.join(", ")}`,
|
|
2772
|
-
* value => `Value: ${value}`
|
|
2773
|
-
* )
|
|
2774
|
-
* );
|
|
2775
|
-
* ```
|
|
2535
|
+
* Extracts the value from a TaskResult by providing handlers for both cases.
|
|
2776
2536
|
*/
|
|
2777
|
-
const fold: <E, A, B>(
|
|
2537
|
+
const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
|
|
2778
2538
|
/**
|
|
2779
|
-
* Pattern matches on a
|
|
2780
|
-
*
|
|
2781
|
-
* @example
|
|
2782
|
-
* ```ts
|
|
2783
|
-
* pipe(
|
|
2784
|
-
* validation,
|
|
2785
|
-
* Validation.match({
|
|
2786
|
-
* passed: value => `Got ${value}`,
|
|
2787
|
-
* failed: errors => `Failed: ${errors.join(", ")}`
|
|
2788
|
-
* })
|
|
2789
|
-
* );
|
|
2790
|
-
* ```
|
|
2539
|
+
* Pattern matches on a TaskResult, returning a Task of the result.
|
|
2791
2540
|
*/
|
|
2792
2541
|
const match: <E, A, B>(cases: {
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
}) => (data:
|
|
2796
|
-
/**
|
|
2797
|
-
* Returns the success value or a default value if the Validation is failed.
|
|
2798
|
-
* The default can be a different type, widening the result to `A | B`.
|
|
2799
|
-
*
|
|
2800
|
-
* @example
|
|
2801
|
-
* ```ts
|
|
2802
|
-
* pipe(Validation.passed(5), Validation.getOrElse(() => 0)); // 5
|
|
2803
|
-
* pipe(Validation.failed("oops"), Validation.getOrElse(() => 0)); // 0
|
|
2804
|
-
* pipe(Validation.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
|
|
2805
|
-
* ```
|
|
2806
|
-
*/
|
|
2807
|
-
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>;
|
|
2808
2545
|
/**
|
|
2809
|
-
*
|
|
2810
|
-
*
|
|
2811
|
-
* @example
|
|
2812
|
-
* ```ts
|
|
2813
|
-
* pipe(
|
|
2814
|
-
* Validation.passed(5),
|
|
2815
|
-
* Validation.tap(n => console.log("Value:", n)),
|
|
2816
|
-
* Validation.map(n => n * 2)
|
|
2817
|
-
* );
|
|
2818
|
-
* ```
|
|
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>`.
|
|
2819
2548
|
*/
|
|
2820
|
-
const
|
|
2549
|
+
const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
|
|
2821
2550
|
/**
|
|
2822
|
-
*
|
|
2823
|
-
*
|
|
2824
|
-
*
|
|
2825
|
-
* @example
|
|
2826
|
-
* ```ts
|
|
2827
|
-
* pipe(
|
|
2828
|
-
* Validation.failed("Name required"),
|
|
2829
|
-
* Validation.tapError(errors => console.error("validation failed:", errors)),
|
|
2830
|
-
* Validation.map(toUser)
|
|
2831
|
-
* );
|
|
2832
|
-
* ```
|
|
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>`.
|
|
2833
2553
|
*/
|
|
2834
|
-
const
|
|
2554
|
+
const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
|
|
2835
2555
|
/**
|
|
2836
|
-
*
|
|
2837
|
-
*
|
|
2838
|
-
* 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.
|
|
2839
2558
|
*/
|
|
2840
|
-
const
|
|
2559
|
+
const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2841
2560
|
/**
|
|
2842
|
-
*
|
|
2843
|
-
*
|
|
2561
|
+
* Executes a side effect on the error value without changing the TaskResult.
|
|
2562
|
+
* Useful for logging or reporting async errors.
|
|
2844
2563
|
*
|
|
2845
2564
|
* @example
|
|
2846
2565
|
* ```ts
|
|
2847
2566
|
* pipe(
|
|
2848
|
-
*
|
|
2849
|
-
*
|
|
2850
|
-
*
|
|
2567
|
+
* fetchUser(id),
|
|
2568
|
+
* TaskResult.tapError(e => console.error("fetch failed:", e)),
|
|
2569
|
+
* TaskResult.chain(saveToCache),
|
|
2570
|
+
* )
|
|
2851
2571
|
* ```
|
|
2852
2572
|
*/
|
|
2853
|
-
const
|
|
2573
|
+
const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2854
2574
|
/**
|
|
2855
|
-
*
|
|
2856
|
-
*
|
|
2857
|
-
*
|
|
2858
|
-
* @example
|
|
2859
|
-
* ```ts
|
|
2860
|
-
* Validation.toResult(Validation.passed(42)); // Ok(42)
|
|
2861
|
-
* Validation.toResult(Validation.failed("oops")); // Err(["oops"])
|
|
2862
|
-
* ```
|
|
2575
|
+
* Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
|
|
2576
|
+
* Both Tasks run in parallel.
|
|
2863
2577
|
*/
|
|
2864
|
-
const
|
|
2578
|
+
const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
|
|
2865
2579
|
/**
|
|
2866
|
-
*
|
|
2867
|
-
*
|
|
2580
|
+
* Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
|
|
2581
|
+
* Use as a terminal step in a `pipe` chain.
|
|
2868
2582
|
*
|
|
2869
2583
|
* @example
|
|
2870
2584
|
* ```ts
|
|
2871
|
-
*
|
|
2872
|
-
*
|
|
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);
|
|
2873
2592
|
* ```
|
|
2874
2593
|
*/
|
|
2875
|
-
const
|
|
2594
|
+
const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Promise<Result<E, A>>;
|
|
2876
2595
|
/**
|
|
2877
|
-
* Converts a
|
|
2878
|
-
*
|
|
2879
|
-
* Useful when bridging from error-short-circuiting `Result` pipelines into
|
|
2880
|
-
* error-accumulating `Validation` pipelines.
|
|
2596
|
+
* Converts a TaskResult value into an object containing a single property.
|
|
2597
|
+
* Initiates the pipeline accumulator record.
|
|
2881
2598
|
*
|
|
2882
2599
|
* @example
|
|
2883
2600
|
* ```ts
|
|
2884
|
-
*
|
|
2885
|
-
* Validation.fromResult(Result.err("bad")); // Failed(["bad"])
|
|
2601
|
+
* pipe(TaskResult.ok(42), TaskResult.bindTo("value")); // TaskResult({ value: 42 })
|
|
2886
2602
|
* ```
|
|
2887
2603
|
*/
|
|
2888
|
-
const
|
|
2604
|
+
const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
|
|
2889
2605
|
/**
|
|
2890
|
-
*
|
|
2891
|
-
* If both are Passed, returns Passed with both values as a tuple.
|
|
2892
|
-
* 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.
|
|
2893
2607
|
*
|
|
2894
2608
|
* @example
|
|
2895
2609
|
* ```ts
|
|
2896
|
-
*
|
|
2897
|
-
*
|
|
2898
|
-
*
|
|
2899
|
-
* ); //
|
|
2900
|
-
*
|
|
2901
|
-
* Validation.product(
|
|
2902
|
-
* Validation.failed("Name required"),
|
|
2903
|
-
* Validation.failed("Age must be >= 0")
|
|
2904
|
-
* ); // 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 })
|
|
2905
2614
|
* ```
|
|
2906
2615
|
*/
|
|
2907
|
-
const
|
|
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; }>;
|
|
2908
2617
|
/**
|
|
2909
|
-
* Combines a
|
|
2910
|
-
*
|
|
2911
|
-
*
|
|
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.
|
|
2912
2621
|
*
|
|
2913
2622
|
* @example
|
|
2914
2623
|
* ```ts
|
|
2915
|
-
*
|
|
2916
|
-
*
|
|
2917
|
-
*
|
|
2918
|
-
*
|
|
2919
|
-
* ]);
|
|
2920
|
-
* // 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 })
|
|
2921
2628
|
* ```
|
|
2922
2629
|
*/
|
|
2923
|
-
const
|
|
2630
|
+
const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskResult<E, R[K]>; }) => TaskResult<E, R>;
|
|
2924
2631
|
}
|
|
2925
2632
|
|
|
2926
2633
|
/**
|
|
@@ -3434,4 +3141,329 @@ declare namespace Tuple {
|
|
|
3434
3141
|
const tap: <A, B>(f: (a: A, b: B) => void) => (tuple: Tuple<A, B>) => Tuple<A, B>;
|
|
3435
3142
|
}
|
|
3436
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
|
+
|
|
3437
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 };
|