functype 0.9.0 → 0.9.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.
Files changed (43) hide show
  1. package/dist/{Either-C-PDWX2U.d.ts → Either-BHep7I0d.d.ts} +7 -2
  2. package/dist/{Serializable-D9GKEo30.d.ts → Serializable-BbKuhDDL.d.ts} +14 -3
  3. package/dist/branded/index.d.ts +4 -6
  4. package/dist/branded/index.mjs +1 -1
  5. package/dist/chunk-GHBOC52G.mjs +43 -0
  6. package/dist/chunk-GHBOC52G.mjs.map +1 -0
  7. package/dist/chunk-R2TQJN3P.mjs +2 -0
  8. package/dist/chunk-R2TQJN3P.mjs.map +1 -0
  9. package/dist/either/index.d.ts +2 -2
  10. package/dist/either/index.mjs +1 -1
  11. package/dist/fpromise/index.d.ts +2 -2
  12. package/dist/fpromise/index.mjs +1 -1
  13. package/dist/index.d.ts +28 -20
  14. package/dist/index.mjs +1 -1
  15. package/dist/list/index.d.ts +2 -2
  16. package/dist/list/index.mjs +1 -1
  17. package/dist/map/index.d.ts +2 -2
  18. package/dist/map/index.mjs +1 -1
  19. package/dist/option/index.d.ts +2 -2
  20. package/dist/option/index.mjs +1 -1
  21. package/dist/set/index.d.ts +2 -2
  22. package/dist/set/index.mjs +1 -1
  23. package/dist/try/index.d.ts +2 -2
  24. package/dist/try/index.mjs +1 -1
  25. package/dist/tuple/index.d.ts +1 -1
  26. package/package.json +3 -3
  27. package/readme/BUNDLE_OPTIMIZATION.md +74 -0
  28. package/readme/FPromise-Assessment.md +43 -0
  29. package/readme/HKT.md +110 -0
  30. package/readme/ROADMAP.md +113 -0
  31. package/readme/TASK-TODO.md +33 -0
  32. package/readme/TUPLE-EXAMPLES.md +76 -0
  33. package/readme/TaskMigration.md +129 -0
  34. package/readme/ai-guide.md +406 -0
  35. package/readme/examples.md +2093 -0
  36. package/readme/quick-reference.md +514 -0
  37. package/readme/task-error-handling.md +283 -0
  38. package/readme/tasks.md +203 -0
  39. package/readme/type-index.md +238 -0
  40. package/dist/chunk-4EYCKDDF.mjs +0 -43
  41. package/dist/chunk-4EYCKDDF.mjs.map +0 -1
  42. package/dist/chunk-V6LFV5LW.mjs +0 -2
  43. package/dist/chunk-V6LFV5LW.mjs.map +0 -1
@@ -0,0 +1,514 @@
1
+ # Functype Quick Reference
2
+
3
+ ## Option<T>
4
+
5
+ ```typescript
6
+ import { Option, Some, None } from "functype/option"
7
+
8
+ // Creation
9
+ Option(42) // Some(42)
10
+ Option(null) // None
11
+ Option(undefined) // None
12
+ Some(42) // Some(42)
13
+ None() // None
14
+ Option.from(42) // Some(42)
15
+ Option.none() // None
16
+
17
+ // Checking
18
+ option.isDefined() // true if Some, false if None
19
+ option.isEmpty() // true if None, false if Some
20
+
21
+ // Accessing
22
+ option.get() // Gets value or throws if None
23
+ option.getOrElse(defaultValue) // Gets value or returns default
24
+ option.getOrElseThrow(new Error("No value")) // Gets value or throws custom error
25
+
26
+ // Transforming
27
+ option.map((x) => x * 2) // Transforms inner value
28
+ option.flatMap((x) => Option(x.toString())) // Chains with operations returning Option
29
+ option.filter((x) => x > 10) // None if predicate fails, unchanged if passes
30
+
31
+ // Pattern matching
32
+ option.fold(
33
+ () => "empty", // Called for None
34
+ (value) => `value: ${value}`, // Called for Some
35
+ )
36
+
37
+ option.match({
38
+ Some: (value) => `value: ${value}`,
39
+ None: () => "empty",
40
+ })
41
+ ```
42
+
43
+ ## Either<L, R>
44
+
45
+ ```typescript
46
+ import { Either, Left, Right } from "functype/either"
47
+
48
+ // Creation
49
+ Right<string, number>(42) // Right<number>(42)
50
+ Left<string, number>("error") // Left<string>("error")
51
+ Either.right(42) // Right(42)
52
+ Either.left("error") // Left("error")
53
+ Either.fromNullable(value, "was null") // Left if null/undefined
54
+
55
+ // Checking
56
+ either.isRight() // true if Right, false if Left
57
+ either.isLeft() // true if Left, false if Right
58
+
59
+ // Accessing
60
+ either.get() // Gets Right value or throws if Left
61
+ either.getOrElse(defaultValue) // Gets Right value or returns default
62
+ either.getLeft() // Gets Left value or throws if Right
63
+
64
+ // Transforming
65
+ either.map((x) => x * 2) // Transforms Right value
66
+ either.mapLeft((e) => `Error: ${e}`) // Transforms Left value
67
+ either.flatMap((x) => Right(x.toString())) // Chains with operations returning Either
68
+ either.filter(
69
+ (x) => x > 10,
70
+ (x) => `${x} is too small`,
71
+ ) // Left if predicate fails
72
+
73
+ // Operations
74
+ either.swap() // Converts Left to Right and vice versa
75
+
76
+ // Pattern matching
77
+ either.fold(
78
+ (left) => `Error: ${left}`,
79
+ (right) => `Success: ${right}`,
80
+ )
81
+
82
+ either.match({
83
+ Right: (value) => `Success: ${value}`,
84
+ Left: (error) => `Error: ${error}`,
85
+ })
86
+ ```
87
+
88
+ ## Try<T>
89
+
90
+ ```typescript
91
+ import { Try, Success, Failure } from "functype/try"
92
+
93
+ // Creation
94
+ Try(() => 42) // Success(42)
95
+ Try(() => {
96
+ throw new Error("Failed")
97
+ }) // Failure(Error)
98
+ Success(42) // Success(42)
99
+ Failure(new Error("Failed")) // Failure(Error)
100
+
101
+ // Checking
102
+ tryVal.isSuccess() // true if Success, false if Failure
103
+ tryVal.isFailure() // true if Failure, false if Success
104
+
105
+ // Accessing
106
+ tryVal.get() // Gets value or throws original error
107
+ tryVal.getOrElse(defaultValue) // Gets value or returns default
108
+ tryVal.error // Gets error for Failure
109
+
110
+ // Error handling
111
+ tryVal.recover(defaultValue) // Success with original value or default
112
+ tryVal.recoverWith(() => Try(() => backup())) // Tries alternative computation on failure
113
+
114
+ // Transforming
115
+ tryVal.map((x) => x * 2) // Maps success value
116
+ tryVal.flatMap((x) => Try(() => operation(x))) // Chains with operations returning Try
117
+
118
+ // Conversions
119
+ tryVal.toOption() // Option.Some for Success, Option.None for Failure
120
+ tryVal.toEither() // Either.Right for Success, Either.Left for Failure
121
+
122
+ // Pattern matching
123
+ tryVal.fold(
124
+ (error) => `Error: ${error.message}`,
125
+ (value) => `Success: ${value}`,
126
+ )
127
+
128
+ tryVal.match({
129
+ Success: (value) => `Success: ${value}`,
130
+ Failure: (error) => `Error: ${error.message}`,
131
+ })
132
+ ```
133
+
134
+ ## List<T>
135
+
136
+ ```typescript
137
+ import { List } from "functype/list"
138
+
139
+ // Creation
140
+ List([1, 2, 3]) // List([1, 2, 3])
141
+ List.empty<number>() // List([])
142
+
143
+ // Properties
144
+ list.isEmpty() // true if empty, false otherwise
145
+ list.size() // Number of elements
146
+
147
+ // Accessing
148
+ list.head() // Option.Some with first element or None if empty
149
+ list.tail() // List with all elements except the first
150
+ list.at(2) // Option.Some with element at index or None
151
+
152
+ // Adding/removing
153
+ list.add(4) // New list with element added
154
+ list.addAll([4, 5, 6]) // New list with elements added
155
+ list.remove(2) // New list with element removed
156
+ list.removeAt(1) // New list with element at index removed
157
+
158
+ // Transforming
159
+ list.map((x) => x * 2) // List with transformed elements
160
+ list.flatMap((x) => List([x, x * 2])) // Transform + flatten
161
+ list.filter((x) => x % 2 === 0) // List with elements matching predicate
162
+
163
+ // Slicing
164
+ list.take(2) // First n elements
165
+ list.drop(2) // All elements after first n
166
+ list.slice(1, 3) // Elements from start to end (exclusive)
167
+
168
+ // Finding
169
+ list.find((x) => x > 10) // Option.Some with first match or None
170
+ list.exists((x) => x > 10) // true if any element matches predicate
171
+ list.forAll((x) => x > 0) // true if all elements match predicate
172
+ list.count((x) => x % 2 === 0) // Count of elements matching predicate
173
+
174
+ // Aggregating
175
+ list.foldLeft(0)((acc, x) => acc + x) // Reduce from left to right
176
+ list.foldRight(0)((x, acc) => x + acc) // Reduce from right to left
177
+ list.reduce((a, b) => a + b) // Reduce (without initial value)
178
+
179
+ // Operations
180
+ list.reverse() // Reversed list
181
+ list.sort((a, b) => a - b) // Sorted list
182
+ list.distinct() // List with duplicates removed
183
+ list.concat(List([4, 5, 6])) // Lists combined
184
+ list.groupBy((x) => (x % 2 === 0 ? "even" : "odd")) // Map of grouped elements
185
+ ```
186
+
187
+ ## Map<K, V>
188
+
189
+ ```typescript
190
+ import { Map } from "functype/map"
191
+
192
+ // Creation
193
+ Map({ a: 1, b: 2, c: 3 }) // Map({a: 1, b: 2, c: 3})
194
+ Map.empty<string, number>() // Empty map
195
+
196
+ // Properties
197
+ map.isEmpty() // true if empty
198
+ map.size() // Number of entries
199
+ map.has("a") // true if key exists
200
+
201
+ // Accessing
202
+ map.get("a") // Option.Some with value or None
203
+ map.getOrElse("a", 0) // Value or default
204
+ map.keys() // List of keys
205
+ map.values() // List of values
206
+ map.entries() // List of [key, value] tuples
207
+
208
+ // Modifying
209
+ map.add("d", 4) // New map with entry added
210
+ map.addAll({ d: 4, e: 5 }) // New map with entries added
211
+ map.remove("a") // New map with key removed
212
+ map.removeAll(["a", "b"]) // New map with keys removed
213
+
214
+ // Transforming
215
+ map.map((v) => v * 2) // Map with transformed values
216
+ map.mapEntries(([k, v]) => [`key_${k}`, v * 2]) // Transform both keys and values
217
+ map.filter((v) => v > 1) // Map with entries matching predicate
218
+ map.filterKeys((k) => k !== "a") // Map with entries having keys matching predicate
219
+
220
+ // Operations
221
+ map.merge(Map({ c: 30, d: 40 })) // Maps combined (right values override)
222
+ map.mergeWith(Map({ c: 30, d: 40 }), (v1, v2) => v1 + v2) // Maps combined with custom function
223
+
224
+ // Conversions
225
+ map.toObject() // Standard JS object
226
+ ```
227
+
228
+ ## Set<T>
229
+
230
+ ```typescript
231
+ import { Set } from "functype/set"
232
+
233
+ // Creation
234
+ Set([1, 2, 3]) // Set([1, 2, 3])
235
+ Set.empty<number>() // Empty set
236
+
237
+ // Properties
238
+ set.isEmpty() // true if empty
239
+ set.size() // Number of elements
240
+ set.has(2) // true if element exists
241
+
242
+ // Modifying
243
+ set.add(4) // New set with element added
244
+ set.addAll([4, 5]) // New set with elements added
245
+ set.remove(2) // New set with element removed
246
+ set.removeAll([1, 2]) // New set with elements removed
247
+
248
+ // Transforming
249
+ set.map((x) => x * 2) // Set with transformed elements
250
+ set.flatMap((x) => Set([x, x + 1])) // Transform + flatten
251
+ set.filter((x) => x % 2 === 0) // Set with elements matching predicate
252
+
253
+ // Set operations
254
+ set.union(Set([3, 4, 5])) // Union of sets
255
+ set.intersect(Set([2, 3, 4])) // Intersection of sets
256
+ set.difference(Set([3, 4])) // Elements in this set but not in other
257
+ set.symmetricDifference(Set([3, 4])) // Elements in either set but not both
258
+ set.isSubsetOf(Set([1, 2, 3, 4])) // true if all elements in other set
259
+ ```
260
+
261
+ ## FPromise<T, E>
262
+
263
+ ```typescript
264
+ import { FPromise } from "functype/fpromise"
265
+
266
+ // Creation
267
+ FPromise.resolve(42) // Resolves with value
268
+ FPromise.reject(new Error()) // Rejects with error
269
+ FPromise.fromPromise(fetch("/api")) // From standard Promise
270
+
271
+ // From functions
272
+ FPromise.tryCatch(
273
+ () => JSON.parse(data),
274
+ (err) => new Error(`Parse error: ${err}`),
275
+ )
276
+
277
+ FPromise.tryCatchAsync(
278
+ async () => await fetch("/api").then((r) => r.json()),
279
+ (err) => new Error(`Fetch error: ${err}`),
280
+ )
281
+
282
+ // Transforming
283
+ promise.map((x) => x * 2) // Transform success value
284
+ promise.mapError((e) => new Error(`Enhanced: ${e}`)) // Transform error
285
+ promise.flatMap((x) => FPromise.resolve(x.toString())) // Chain with another FPromise
286
+
287
+ // Error handling
288
+ promise.recover(defaultValue) // Default if rejected
289
+ promise.recoverWith((err) => FPromise.resolve(`Recovered from ${err}`)) // Alternative promise on error
290
+
291
+ // Side effects
292
+ promise.tap((value) => console.log(value)) // Side effect on success
293
+ promise.tapError((err) => console.error(err)) // Side effect on error
294
+
295
+ // Combining
296
+ FPromise.all([p1, p2, p3]) // All promises succeed
297
+ FPromise.race([p1, p2]) // First to resolve
298
+ FPromise.any([p1, p2]) // First to resolve successfully
299
+
300
+ // Timeouts
301
+ FPromise.timeout(promise, 1000, () => new Error("Timed out")) // Rejects if promise takes too long
302
+
303
+ // Pattern matching
304
+ promise.fold(
305
+ (err) => `Error: ${err}`,
306
+ (val) => `Success: ${val}`,
307
+ ) // Handle both outcomes
308
+
309
+ // Conversion
310
+ promise.toPromise() // Convert to standard Promise
311
+ ```
312
+
313
+ ## Task
314
+
315
+ ```typescript
316
+ import { Task } from "functype/core/task"
317
+
318
+ // Synchronous tasks
319
+ const syncTask = Task().Sync(
320
+ () => 42,
321
+ (err) => new Error(`Failed: ${err}`),
322
+ )
323
+
324
+ // Asynchronous tasks
325
+ const asyncTask = Task().Async(
326
+ async () => await fetch("/api").then((r) => r.json()),
327
+ async (err) => new Error(`Fetch failed: ${err}`),
328
+ )
329
+
330
+ // Named tasks (for debugging and error identification)
331
+ const namedTask = Task({ name: "UserFetch" }).Sync(
332
+ () => ({ id: 1, name: "John" }),
333
+ (err) => new Error(`User fetch failed: ${err}`),
334
+ )
335
+
336
+ // Error handling with named tasks
337
+ try {
338
+ await Task({ name: "DataProcessor" }).Async(() => {
339
+ throw new Error("Processing failed")
340
+ })
341
+ } catch (error) {
342
+ console.log(error.name) // "DataProcessor"
343
+ console.log(error.taskInfo.name) // "DataProcessor"
344
+ }
345
+
346
+ // Companion functions
347
+ Task.success(42, { name: "SuccessResult" }) // Creates TaskResult
348
+ Task.fail(new Error("Failed"), data, { name: "FailureResult" }) // Creates TaskException with name
349
+
350
+ // Adapting functions
351
+ const fetchAPI = (id: string): Promise<User> => fetch(`/api/users/${id}`).then((r) => r.json())
352
+ const getUser = Task.fromPromise(fetchAPI, { name: "UserFetch" })
353
+
354
+ // Converting
355
+ const promise = Task.toPromise(syncTask) // Standard Promise
356
+ ```
357
+
358
+ ## Tuple
359
+
360
+ ```typescript
361
+ import { Tuple } from "functype/tuple"
362
+
363
+ // Creation
364
+ const pair = Tuple(42, "hello")
365
+ const triple = Tuple(true, 42, "hello")
366
+
367
+ // Accessing
368
+ pair.first() // 42
369
+ pair.second() // "hello"
370
+ triple.third() // "hello"
371
+ pair.toArray() // [42, "hello"]
372
+
373
+ // Transforming
374
+ pair.mapFirst((x) => x * 2) // Tuple(84, "hello")
375
+ pair.mapSecond((s) => s.toUpperCase()) // Tuple(42, "HELLO")
376
+ pair.map(([a, b]) => [a * 2, b.toUpperCase()]) // Tuple(84, "HELLO")
377
+
378
+ // Operations
379
+ pair.swap() // Tuple("hello", 42)
380
+ pair.apply((a, b) => a + b.length) // 47
381
+
382
+ // Combining
383
+ pair.concat(Tuple(true)) // Tuple(42, "hello", true)
384
+ ```
385
+
386
+ ## Branded Types
387
+
388
+ ```typescript
389
+ import { Brand } from "functype/branded"
390
+
391
+ // Type definitions
392
+ type UserId = Brand<string, "UserId">
393
+ type Email = Brand<string, "Email">
394
+ type PositiveInt = Brand<number, "PositiveInt">
395
+
396
+ // Factory functions with validation
397
+ const UserId = (id: string): UserId => {
398
+ if (!/^U\d{6}$/.test(id)) throw new Error("Invalid ID format")
399
+ return id as UserId
400
+ }
401
+
402
+ const PositiveInt = (n: number): PositiveInt => {
403
+ if (!Number.isInteger(n) || n <= 0) throw new Error("Not a positive integer")
404
+ return n as PositiveInt
405
+ }
406
+
407
+ // Usage
408
+ function getUserById(id: UserId): User {
409
+ /* ... */
410
+ }
411
+
412
+ // Type-safe calls
413
+ getUserById(UserId("U123456")) // Works
414
+ // getUserById("U123456") // Type error: string is not UserId
415
+ ```
416
+
417
+ ## Pattern Matching
418
+
419
+ ```typescript
420
+ import { Option, Either, Try, List, MatchableUtils } from "functype"
421
+
422
+ // Built-in pattern matching
423
+ option.match({
424
+ Some: (value) => `Found: ${value}`,
425
+ None: () => "Not found",
426
+ })
427
+
428
+ either.match({
429
+ Right: (value) => `Success: ${value}`,
430
+ Left: (error) => `Error: ${error}`,
431
+ })
432
+
433
+ list.match({
434
+ NonEmpty: (values) => `Values: ${values.join(", ")}`,
435
+ Empty: () => "No values",
436
+ })
437
+
438
+ // Custom pattern matching
439
+ const isPositive = MatchableUtils.when(
440
+ (n: number) => n > 0,
441
+ (n) => `Positive: ${n}`,
442
+ )
443
+
444
+ const isZero = MatchableUtils.when(
445
+ (n: number) => n === 0,
446
+ () => "Zero",
447
+ )
448
+
449
+ const isNegative = MatchableUtils.when(
450
+ (n: number) => n < 0,
451
+ (n) => `Negative: ${n}`,
452
+ )
453
+
454
+ const defaultCase = MatchableUtils.default((x: number) => `Default: ${x}`)
455
+
456
+ // Chain patterns with fallbacks
457
+ isPositive(42) ?? isZero(42) ?? isNegative(42) ?? defaultCase(42) // "Positive: 42"
458
+ ```
459
+
460
+ ## Common Conversions
461
+
462
+ ```typescript
463
+ import { Option, Either, Try, List, FoldableUtils } from "functype"
464
+
465
+ // Convert between types
466
+ FoldableUtils.toList(Option(42)) // List([42])
467
+ FoldableUtils.toList(Either.right(42)) // List([42])
468
+ FoldableUtils.toList(Try(() => 42)) // List([42])
469
+
470
+ FoldableUtils.toOption(List([1, 2, 3])) // Some(1)
471
+ FoldableUtils.toOption(Either.right(42)) // Some(42)
472
+ FoldableUtils.toOption(Try(() => 42)) // Some(42)
473
+
474
+ FoldableUtils.toEither(Option(42), "Empty") // Right(42)
475
+ FoldableUtils.toEither(
476
+ Try(() => 42),
477
+ "Failed",
478
+ ) // Right(42)
479
+
480
+ // Built-in conversions
481
+ option.toEither("No value") // Either.Right or Either.Left
482
+ either.toOption() // Option.Some or Option.None
483
+ tryVal.toEither() // Either.Right or Either.Left with error
484
+ tryVal.toOption() // Option.Some or Option.None
485
+ ```
486
+
487
+ ## Functional Composition
488
+
489
+ ```typescript
490
+ import { pipe } from "functype/pipe"
491
+
492
+ // Pipe operations for cleaner sequential transformations
493
+ const result = pipe(
494
+ Option("42"),
495
+ (opt) => opt.map((s) => s.trim()),
496
+ (opt) => opt.map((s) => parseInt(s, 10)),
497
+ (opt) => opt.filter((n) => !isNaN(n)),
498
+ (opt) => opt.map((n) => n * 2),
499
+ (opt) => opt.getOrElse(0),
500
+ ) // 84
501
+
502
+ // Cross-type transformations
503
+ const mixed = pipe(
504
+ Option("42"),
505
+ (opt) => opt.map((s) => parseInt(s, 10)),
506
+ (opt) => opt.toEither("Invalid number"),
507
+ (e) => e.map((n) => n * 2),
508
+ (e) =>
509
+ e.fold(
510
+ (err) => `Error: ${err}`,
511
+ (val) => `Result: ${val}`,
512
+ ),
513
+ ) // "Result: 84"
514
+ ```