functype 0.60.3 → 0.60.5

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.
@@ -0,0 +1,384 @@
1
+ # AI Guide to Functype
2
+
3
+ This document provides a concise reference for AI models to understand the patterns and usage of the Functype library.
4
+
5
+ ## Core Types
6
+
7
+ ### Option<T>
8
+
9
+ ```typescript
10
+ // Create: Option(value) returns Some(value) or None
11
+ const some = Option(42) // Some(42)
12
+ const none = Option(null) // None
13
+
14
+ // Access: .get() or .orElse(default)
15
+ some.get() // 42
16
+ none.orElse("default") // "default"
17
+
18
+ // Transform: .map(), .flatMap(), .filter()
19
+ some.map((x) => x * 2) // Some(84)
20
+ some.flatMap((x) => Option(x.toString())) // Some("42")
21
+ some.filter((x) => x > 50) // None
22
+
23
+ // Pattern match: .fold() or .match()
24
+ some.fold(
25
+ () => "empty",
26
+ (val) => `value: ${val}`,
27
+ ) // "value: 42"
28
+ ```
29
+
30
+ ### Either<L, R>
31
+
32
+ ```typescript
33
+ // Create: Right(value) or Left(error)
34
+ const right = Right<string, number>(42)
35
+ const left = Left<string, number>("error")
36
+
37
+ // From functions: Either.tryCatch()
38
+ const result = Either.tryCatch(
39
+ () => JSON.parse('{"key":"value"}'),
40
+ (err) => `Parse error: ${err}`,
41
+ ) // Right({key: "value"})
42
+
43
+ // Transform: .map(), .mapLeft(), .flatMap()
44
+ right.map((x) => x * 2) // Right(84)
45
+ left.mapLeft((e) => e.toUpperCase()) // Left("ERROR")
46
+ right.flatMap((x) => Right(x.toString())) // Right("42")
47
+
48
+ // Pattern match: .fold() or .match()
49
+ right.fold(
50
+ (err) => `Error: ${err}`,
51
+ (val) => `Success: ${val}`,
52
+ ) // "Success: 42"
53
+ ```
54
+
55
+ ### Try<T>
56
+
57
+ ```typescript
58
+ // Create: Try(() => potentially_throwing_function())
59
+ const success = Try(() => 42)
60
+ const failure = Try(() => {
61
+ throw new Error("Failed")
62
+ })
63
+
64
+ // Transform: .map(), .flatMap(), .recover()
65
+ success.map((x) => x * 2) // Success(84)
66
+ failure.recover("default") // Success("default")
67
+ success.flatMap((x) => Try(() => x.toString())) // Success("42")
68
+
69
+ // Pattern match: .fold() or .match()
70
+ success.fold(
71
+ (err) => `Error: ${err.message}`,
72
+ (val) => `Success: ${val}`,
73
+ ) // "Success: 42"
74
+ ```
75
+
76
+ ### List<T>
77
+
78
+ ```typescript
79
+ // Create: List([...elements])
80
+ const list = List([1, 2, 3, 4, 5])
81
+
82
+ // Access: .head(), .tail(), .at(index)
83
+ list.head() // Some(1)
84
+ list.tail() // List([2, 3, 4, 5])
85
+
86
+ // Transform: .map(), .flatMap(), .filter()
87
+ list.map((x) => x * 2) // List([2, 4, 6, 8, 10])
88
+ list.filter((x) => x % 2 === 0) // List([2, 4])
89
+ list.flatMap((x) => List([x, x])) // List([1, 1, 2, 2, 3, 3, 4, 4, 5, 5])
90
+
91
+ // Reduce: .foldLeft(), .foldRight()
92
+ list.foldLeft(0)((acc, x) => acc + x) // 15
93
+ ```
94
+
95
+ ### Map<K, V>
96
+
97
+ ```typescript
98
+ // Create: Map({key: value})
99
+ const map = Map({ a: 1, b: 2, c: 3 })
100
+
101
+ // Access: .get(key), .orElse(key, default)
102
+ map.get("a") // Some(1)
103
+ map.orElse("d", 0) // 0
104
+
105
+ // Transform: .map(), .filter()
106
+ map.map((v) => v * 2) // Map({a: 2, b: 4, c: 6})
107
+ map.filter((v) => v > 1) // Map({b: 2, c: 3})
108
+ ```
109
+
110
+ ### Set<T>
111
+
112
+ ```typescript
113
+ // Create: Set([...elements])
114
+ const set = Set([1, 2, 3, 4, 5])
115
+
116
+ // Operations: .add(), .remove(), .has()
117
+ set.add(6) // Set([1, 2, 3, 4, 5, 6])
118
+ set.remove(3) // Set([1, 2, 4, 5])
119
+ set.has(2) // true
120
+
121
+ // Set operations: .union(), .intersect(), .difference()
122
+ const set2 = Set([4, 5, 6, 7])
123
+ set.union(set2) // Set([1, 2, 3, 4, 5, 6, 7])
124
+ set.intersect(set2) // Set([4, 5])
125
+ ```
126
+
127
+ ### Task
128
+
129
+ ```typescript
130
+ // Create: Task().Sync() or Task().Async()
131
+ const syncTask = Task().Sync(
132
+ () => 42,
133
+ (err) => new Error(`Failed: ${err}`),
134
+ )
135
+
136
+ const asyncTask = Task().Async(
137
+ async () => await fetchData(),
138
+ async (err) => new Error(`Fetch failed: ${err}`),
139
+ )
140
+
141
+ // From promise
142
+ const fetchUser = Task({ name: "UserFetch" }).fromPromise(fetchUserAPI)
143
+
144
+ // Usage
145
+ syncTask.then((value) => console.log(value)).catch((error) => console.error(error))
146
+ ```
147
+
148
+ ### Tuple
149
+
150
+ ```typescript
151
+ // Create: Tuple(...values)
152
+ const pair = Tuple(42, "hello")
153
+
154
+ // Access: .first(), .second(), etc.
155
+ pair.first() // 42
156
+ pair.second() // "hello"
157
+
158
+ // Transform: .map(), .mapFirst(), .mapSecond()
159
+ pair.mapFirst((x) => x * 2) // Tuple(84, "hello")
160
+ ```
161
+
162
+ ## Common Patterns
163
+
164
+ ### Type Safety
165
+
166
+ ```typescript
167
+ // Branded types
168
+ type UserId = Brand<string, "UserId">
169
+ const UserId = (id: string): UserId => {
170
+ if (!/^U\d{6}$/.test(id)) throw new Error("Invalid ID format")
171
+ return id as UserId
172
+ }
173
+
174
+ // Type-safe functions
175
+ function getUserById(id: UserId): User {
176
+ /* ... */
177
+ }
178
+ getUserById(UserId("U123456")) // Works
179
+ getUserById("U123456") // Type error
180
+ ```
181
+
182
+ ### Error Handling
183
+
184
+ ```typescript
185
+ // Option for nullable values
186
+ const maybeUser = Option(findUser(id))
187
+ maybeUser.fold(
188
+ () => console.log("User not found"),
189
+ (user) => console.log("User:", user.name),
190
+ )
191
+
192
+ // Either for errors with context
193
+ const validationResult = validateForm(formData)
194
+ validationResult.fold(
195
+ (errors) => handleErrors(errors),
196
+ (data) => processForm(data),
197
+ )
198
+
199
+ // Try for exception safety
200
+ const parseResult = Try(() => JSON.parse(input))
201
+ parseResult.fold(
202
+ (err) => console.error("Parse error:", err.message),
203
+ (data) => console.log("Data:", data),
204
+ )
205
+ ```
206
+
207
+ ### Chaining Operations
208
+
209
+ ```typescript
210
+ // Option chain
211
+ const userCity = Option(user)
212
+ .flatMap((u) => Option(u.address))
213
+ .flatMap((a) => Option(a.city))
214
+ .orElse("Unknown")
215
+
216
+ // Either chain
217
+ parseInput(input)
218
+ .flatMap(validateData)
219
+ .flatMap(transformData)
220
+ .fold(
221
+ (err) => handleError(err),
222
+ (result) => displayResult(result),
223
+ )
224
+
225
+ // List processing
226
+ List([1, 2, 3, 4, 5])
227
+ .filter((n) => n % 2 === 0)
228
+ .map((n) => n * n)
229
+ .foldLeft(0)((acc, n) => acc + n) // 20 (4 + 16)
230
+ ```
231
+
232
+ ### Pattern Matching
233
+
234
+ ```typescript
235
+ // Using match method
236
+ result.match({
237
+ Some: (value) => `Found: ${value}`,
238
+ None: () => "Not found",
239
+ })
240
+
241
+ // Using fold method
242
+ either.fold(
243
+ (left) => `Error: ${left}`,
244
+ (right) => `Success: ${right}`,
245
+ )
246
+
247
+ // Using MatchableUtils
248
+ const isPositive = MatchableUtils.when(
249
+ (n: number) => n > 0,
250
+ (n) => `Positive: ${n}`,
251
+ )
252
+
253
+ const isNegative = MatchableUtils.when(
254
+ (n: number) => n < 0,
255
+ (n) => `Negative: ${n}`,
256
+ )
257
+
258
+ const defaultCase = MatchableUtils.default((n: number) => `Zero: ${n}`)
259
+
260
+ // Usage
261
+ isPositive(42) ?? isNegative(42) ?? defaultCase(42) // "Positive: 42"
262
+ ```
263
+
264
+ ### Functional Composition
265
+
266
+ ```typescript
267
+ // Using pipe for sequential operations
268
+ import { pipe } from "functype"
269
+
270
+ const result = pipe(
271
+ Option(input),
272
+ (opt) => opt.map((s) => s.trim()),
273
+ (opt) => opt.filter((s) => s.length > 0),
274
+ (opt) => opt.map((s) => parseInt(s, 10)),
275
+ (opt) => opt.filter((n) => !isNaN(n)),
276
+ (opt) => opt.orElse(0),
277
+ )
278
+
279
+ // Converting between types
280
+ import { FoldableUtils } from "functype"
281
+
282
+ const optionAsList = FoldableUtils.toList(option)
283
+ const listAsOption = FoldableUtils.toOption(list)
284
+ const tryAsEither = FoldableUtils.toEither(tryVal, "Default error")
285
+ ```
286
+
287
+ ## Key Principles
288
+
289
+ 1. **Immutability**: All data structures return new instances when modified
290
+ 2. **Type Safety**: Strong TypeScript typing throughout the library
291
+ 3. **Null Safety**: No null/undefined values within containers (Option, Either, etc.)
292
+ 4. **Error Handling**: Explicit error handling using functional patterns
293
+ 5. **Pattern Matching**: Consistent APIs for inspecting and handling variants
294
+ 6. **Composability**: Methods designed for chaining and composition
295
+ 7. **Consistency**: Similar patterns across different data structures
296
+
297
+ ## Common Imports
298
+
299
+ ```typescript
300
+ // Full package import (not recommended for production)
301
+ import { Option, Either, Try, List } from "functype"
302
+
303
+ // Optimized imports for tree-shaking
304
+ import { Option } from "functype/option"
305
+ import { Either } from "functype/either"
306
+ import { List } from "functype/list"
307
+
308
+ // Individual constructor imports
309
+ import { some, none } from "functype/option"
310
+ import { right, left } from "functype/either"
311
+ ```
312
+
313
+ ## Type Class Hierarchy
314
+
315
+ - **Functor**: `map` - Transform values while preserving structure
316
+ - **Applicative**: Apply functions inside containers
317
+ - **Monad**: `flatMap` - Chain operations that return containerized values
318
+ - **Foldable**: `fold`, `foldLeft`, `foldRight` - Collapse structure
319
+ - **Traversable**: Convert/sequence containers
320
+
321
+ ## Anti-Patterns to Avoid
322
+
323
+ 1. ❌ **Unnecessary Unwrapping**:
324
+
325
+ ```typescript
326
+ // Bad
327
+ if (option.isDefined()) {
328
+ doSomething(option.get())
329
+ } else {
330
+ doSomethingElse()
331
+ }
332
+
333
+ // Good
334
+ option.fold(
335
+ () => doSomethingElse(),
336
+ (value) => doSomething(value),
337
+ )
338
+ ```
339
+
340
+ 2. ❌ **Throwing from Inside Containers**:
341
+
342
+ ```typescript
343
+ // Bad
344
+ option.map((value) => {
345
+ if (!isValid(value)) throw new Error("Invalid")
346
+ return transform(value)
347
+ })
348
+
349
+ // Good
350
+ option.flatMap((value) => (isValid(value) ? Option(transform(value)) : Option(null)))
351
+ ```
352
+
353
+ 3. ❌ **Not Using Composition**:
354
+
355
+ ```typescript
356
+ // Bad
357
+ const a = option.map((x) => x + 1)
358
+ const b = a.filter((x) => x > 10)
359
+ const c = b.orElse(0)
360
+
361
+ // Good
362
+ const result = option
363
+ .map((x) => x + 1)
364
+ .filter((x) => x > 10)
365
+ .orElse(0)
366
+ ```
367
+
368
+ 4. ❌ **Mixing Imperative and Functional Styles**:
369
+
370
+ ```typescript
371
+ // Bad
372
+ let result = 0
373
+ option.fold(
374
+ () => {
375
+ result = 42
376
+ },
377
+ (value) => {
378
+ result = value
379
+ },
380
+ )
381
+
382
+ // Good
383
+ const result = option.orElse(42)
384
+ ```