functype 0.8.83 → 0.8.85

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 (38) hide show
  1. package/dist/{Either-CncND8cm.d.ts → Either-BlY4VB1r.d.ts} +3 -3
  2. package/dist/{chunk-JMCOLAJY.mjs → chunk-JAPOUVPL.mjs} +2 -2
  3. package/dist/chunk-JAPOUVPL.mjs.map +1 -0
  4. package/dist/either/index.d.ts +1 -1
  5. package/dist/either/index.mjs +1 -1
  6. package/dist/fpromise/index.d.ts +1 -1
  7. package/dist/fpromise/index.mjs +1 -1
  8. package/dist/index.d.ts +3 -28
  9. package/dist/index.mjs +1 -1
  10. package/dist/list/index.d.ts +1 -1
  11. package/dist/list/index.mjs +1 -1
  12. package/dist/map/index.d.ts +1 -1
  13. package/dist/map/index.mjs +1 -1
  14. package/dist/option/index.d.ts +1 -1
  15. package/dist/option/index.mjs +1 -1
  16. package/dist/set/index.d.ts +1 -1
  17. package/dist/set/index.mjs +1 -1
  18. package/dist/try/index.d.ts +1 -1
  19. package/dist/try/index.mjs +1 -1
  20. package/package.json +1 -1
  21. package/dist/chunk-JMCOLAJY.mjs.map +0 -1
  22. package/readme/BUNDLE_OPTIMIZATION.md +0 -74
  23. package/readme/FPromise-Assessment.md +0 -43
  24. package/readme/HKT.md +0 -110
  25. package/readme/ROADMAP.md +0 -113
  26. package/readme/TASK-IMPLEMENTATION.md +0 -290
  27. package/readme/TASK-TODO.md +0 -40
  28. package/readme/TASK-UPDATES.md +0 -64
  29. package/readme/TUPLE-EXAMPLES.md +0 -76
  30. package/readme/TaskMigration.md +0 -129
  31. package/readme/ai-guide.md +0 -406
  32. package/readme/examples.md +0 -2093
  33. package/readme/quick-reference.md +0 -514
  34. package/readme/task-cancellation-progress.md +0 -258
  35. package/readme/task-error-handling.md +0 -127
  36. package/readme/task-quick-reference.md +0 -157
  37. package/readme/tasks.md +0 -205
  38. package/readme/type-index.md +0 -238
@@ -1,64 +0,0 @@
1
- # Task Module Updates Summary
2
-
3
- ## Overview of Enhancements
4
-
5
- We've made the following significant enhancements to the Task module:
6
-
7
- 1. **Implemented Task.race** - For racing multiple tasks with timeout support
8
- 2. **Added Task.fromNodeCallback** - For Node.js-style callback integration
9
- 3. **Implemented Cancellation Support** - For stopping long-running operations
10
- 4. **Added Progress Tracking** - For monitoring operation completion status
11
- 5. **Comprehensive Tests** - Including property-based tests and edge case handling
12
-
13
- ## Documentation Updates
14
-
15
- The following new documentation has been created:
16
-
17
- 1. **[TASK-IMPLEMENTATION.md](../docs/TASK-IMPLEMENTATION.md)** - Deep analysis of Task design considerations and trade-offs
18
- 2. **[task-cancellation-progress.md](task-cancellation-progress.md)** - Guide to using cancellation and progress features
19
- 3. **[task-quick-reference.md](task-quick-reference.md)** - Compact reference for all Task functionality
20
-
21
- ## Current Status
22
-
23
- The Task implementation now:
24
-
25
- - Provides a robust bridge between functional patterns and async operations
26
- - Seamlessly integrates with existing Promise-based and Node.js callback APIs
27
- - Supports cancellation with proper resource cleanup
28
- - Tracks progress for long-running operations
29
- - Maintains rich error context throughout the operation lifecycle
30
- - Follows functional programming principles
31
-
32
- ## Recommendations for Integration
33
-
34
- ### Documentation Recommendations
35
-
36
- 1. **Update quick-reference.md**: Add Task section based on task-quick-reference.md
37
- 2. **Update TASK-TODO.md**: Mark newly implemented items as completed
38
- 3. **Update tasks.md**: Mark cancellation and Node.js callback items as completed
39
-
40
- ### Implementation Recommendations
41
-
42
- 1. **Error Context Preservation**: Consider an option to preserve innermost task context
43
- 2. **Timeout Support**: Add global timeout support for any task operation
44
- 3. **Structured Resource Management**: Implement a `Task.using` pattern for guaranteed cleanup
45
- 4. **Lightweight Mode**: Consider a performance-optimized Task variant for hot paths
46
-
47
- ## Next Steps
48
-
49
- Based on the existing roadmap and our implementation, these items could be prioritized:
50
-
51
- 1. **Error Aggregation for Parallel Operations**: For collecting multiple errors when running tasks in parallel
52
- 2. **Task Scope API**: For structured concurrency patterns with linked task lifecycles
53
- 3. **Framework Integration**: Create React/Vue hooks for Task management
54
- 4. **Performance Monitoring**: Add performance tracking capabilities to tasks
55
-
56
- ## Testing Observations
57
-
58
- During the implementation and testing process, we discovered:
59
-
60
- 1. **Task Nesting Behavior**: Outer task context overwrites inner task context in errors
61
- 2. **Cancellation Edge Cases**: Some race conditions exist in rapidly cancelled tasks
62
- 3. **Testing Challenges**: Timing-dependent tests require careful structuring
63
-
64
- Overall, the Task implementation is now significantly more robust and feature-complete, providing a strong foundation for asynchronous functional programming in TypeScript.
@@ -1,76 +0,0 @@
1
- # Tuple Enhanced with Modern TypeScript Features
2
-
3
- ## What's Improved
4
-
5
- Our enhanced `Tuple` implementation leverages modern TypeScript features:
6
-
7
- 1. **Const type parameters** (TypeScript 5.0+)
8
- 2. **Variadic tuple types** (TypeScript 4.0+)
9
- 3. **Stronger type inference** for tuple elements
10
-
11
- ## Examples
12
-
13
- ### Basic Usage
14
-
15
- ```typescript
16
- import { Tuple } from "@/tuple"
17
-
18
- // Create a tuple with mixed types
19
- const personTuple = Tuple(["John Doe", 42, true])
20
-
21
- // Access values with type safety
22
- const name = personTuple.get(0) // Type is string
23
- const age = personTuple.get(1) // Type is number
24
- const active = personTuple.get(2) // Type is boolean
25
-
26
- // Transform the tuple
27
- const mapped = personTuple.map((values) => values.map((x) => (typeof x === "number" ? x * 2 : x)))
28
- ```
29
-
30
- ### Preserving Literal Types
31
-
32
- ```typescript
33
- // Using 'as const' with the enhanced implementation
34
- const literalTuple = Tuple([1, "hello", true] as const)
35
-
36
- // TypeScript now knows the exact types:
37
- const first = literalTuple.get(0) // Type is exactly 1 (not just number)
38
- const second = literalTuple.get(1) // Type is exactly 'hello' (not just string)
39
- const third = literalTuple.get(2) // Type is exactly true (not just boolean)
40
-
41
- // Benefits:
42
- // - Better type checking
43
- // - Autocomplete shows exact values
44
- // - Prevents invalid index access
45
- ```
46
-
47
- ### Type-Level Utilities (for future improvements)
48
-
49
- ```typescript
50
- // Example of potential future type utilities
51
- type FirstElement<T extends Tuple<unknown[]>> = T extends Tuple<[infer F, ...unknown[]]> ? F : never
52
-
53
- // Extract first element's type
54
- type First = FirstElement<typeof literalTuple> // Would be 1
55
-
56
- // Could expand to other utilities like:
57
- // - LastElement
58
- // - RemoveFirst
59
- // - Prepend<T, Item>
60
- // - etc.
61
- ```
62
-
63
- ## When Is This Useful?
64
-
65
- 1. **Strong typing for heterogeneous collections**:
66
- - When you need to store different types in a fixed structure
67
- - When you want type safety beyond what arrays provide
68
-
69
- 2. **APIs returning fixed-length, mixed-type results**:
70
- - When a function returns multiple values of different types
71
-
72
- 3. **Data transformation pipelines**:
73
- - When you need to transform data while preserving type information
74
-
75
- 4. **Configuration objects with fixed format**:
76
- - When config must follow a specific format with specific types at each position
@@ -1,129 +0,0 @@
1
- # Task Migration Guide
2
-
3
- This guide demonstrates how to migrate traditional Promise-based code to the functional `Task` pattern in the functype library.
4
-
5
- ## The Problem with Traditional Promises
6
-
7
- Traditional JavaScript/TypeScript Promise-based code often suffers from:
8
-
9
- 1. Implicit error handling (errors silently propagate)
10
- 2. Hard-to-trace error stacks
11
- 3. Mixed error types without type safety
12
- 4. Verbose try/catch blocks
13
- 5. Side effects spread throughout the codebase
14
-
15
- ## Migration Path: Traditional Promises → Task
16
-
17
- ### Step 1: Identify Promise-Based Code
18
-
19
- ```typescript
20
- // Traditional promise-based API call
21
- function fetchUserData(userId: string): Promise<UserData> {
22
- return fetch(`/api/users/${userId}`).then((response) => {
23
- if (!response.ok) {
24
- throw new Error(`Failed to fetch user: ${response.statusText}`)
25
- }
26
- return response.json()
27
- })
28
- }
29
-
30
- // Usage with promise chains
31
- function displayUserProfile(userId: string): Promise<void> {
32
- return fetchUserData(userId)
33
- .then((userData) => {
34
- renderProfile(userData)
35
- })
36
- .catch((error) => {
37
- showErrorMessage(error)
38
- })
39
- }
40
- ```
41
-
42
- ### Step 2: Convert to Task with fromPromise adapter
43
-
44
- ```typescript
45
- import { Task } from "@/core/task/Task"
46
-
47
- // Step 1: Create a Task wrapper
48
- const userTask = Task<UserData>({ name: "UserOperations" })
49
-
50
- // Step 2: Convert promise function to Task function
51
- const fetchUserData = (userId: string): FPromise<UserData> => {
52
- return userTask.fromPromise((id: string) =>
53
- fetch(`/api/users/${id}`).then((response) => {
54
- if (!response.ok) {
55
- throw new Error(`Failed to fetch user: ${response.statusText}`)
56
- }
57
- return response.json()
58
- }),
59
- )(userId)
60
- }
61
-
62
- // Step 3: Use in Task-based workflow
63
- const displayUserProfile = (userId: string): FPromise<void> => {
64
- return fetchUserData(userId)
65
- .then((userData) => {
66
- renderProfile(userData)
67
- return undefined
68
- })
69
- .catch((error) => {
70
- showErrorMessage(error)
71
- return undefined
72
- })
73
- }
74
- ```
75
-
76
- ### Step 3: Fully Embrace the Functional Pattern
77
-
78
- ```typescript
79
- import { Task, TaskResult, TaskException } from "@/core/task/Task"
80
- import { Either } from "@/either/Either"
81
- import { Throwable } from "@/core/throwable/Throwable"
82
-
83
- // Create a domain-specific Task
84
- const userTask = Task<UserData>({ name: "UserOperations" })
85
-
86
- // Fully functional API
87
- const fetchUserData = (userId: string): FPromise<Either<Throwable, UserData>> => {
88
- return FPromise<Either<Throwable, UserData>>(async (resolve) => {
89
- try {
90
- const response = await fetch(`/api/users/${userId}`)
91
- if (!response.ok) {
92
- resolve(userTask.fail(new Error(`Failed to fetch user: ${response.statusText}`)))
93
- return
94
- }
95
- const data = await response.json()
96
- resolve(userTask.success(data))
97
- } catch (error) {
98
- resolve(userTask.fail(error))
99
- }
100
- })
101
- }
102
-
103
- // Functional composition with proper error handling
104
- const displayUserProfile = (userId: string): FPromise<void> => {
105
- return fetchUserData(userId).then((result) => {
106
- if (result.isRight()) {
107
- renderProfile(result.get())
108
- } else {
109
- showErrorMessage(result.get())
110
- }
111
- })
112
- }
113
- ```
114
-
115
- ## Benefits of Task-Based Approach
116
-
117
- 1. **Explicit Error Handling**: Errors are represented as values in the Either type
118
- 2. **Type Safety**: Error and success paths are fully typed
119
- 3. **Composition**: Tasks can be composed with other functional patterns
120
- 4. **Interoperability**: Can work with existing Promise-based code
121
- 5. **Testability**: Pure functions are easier to test
122
-
123
- ## Best Practices
124
-
125
- 1. Use descriptive names for Tasks that reflect their domain purpose
126
- 2. Leverage the `fromPromise` adapter for gradual migration
127
- 3. Combine with Either for full type safety in error handling
128
- 4. Use `toPromise` when integrating back with traditional Promise-based APIs
129
- 5. Keep Task operations pure when possible
@@ -1,406 +0,0 @@
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 .getOrElse(default)
15
- some.get() // 42
16
- none.getOrElse("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), .getOrElse(key, default)
102
- map.get("a") // Some(1)
103
- map.getOrElse("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
- ### FPromise<T, E>
128
-
129
- ```typescript
130
- // Create: FPromise.resolve(), FPromise.reject(), FPromise.tryCatch()
131
- const success = FPromise.resolve(42)
132
- const failure = FPromise.reject(new Error("Failed"))
133
-
134
- // From async functions
135
- const result = FPromise.tryCatchAsync(
136
- async () => await fetchData(),
137
- (err) => new Error(`Fetch failed: ${err}`),
138
- )
139
-
140
- // Transform: .map(), .mapError(), .flatMap()
141
- success.map((x) => x * 2) // FPromise<84, never>
142
- failure.mapError((e) => new Error(`Enhanced: ${e.message}`))
143
- success.flatMap((x) => FPromise.resolve(x.toString()))
144
-
145
- // Error handling
146
- failure.recover("default") // FPromise<"default", never>
147
- ```
148
-
149
- ### Task
150
-
151
- ```typescript
152
- // Create: Task().Sync() or Task().Async()
153
- const syncTask = Task().Sync(
154
- () => 42,
155
- (err) => new Error(`Failed: ${err}`),
156
- )
157
-
158
- const asyncTask = Task().Async(
159
- async () => await fetchData(),
160
- async (err) => new Error(`Fetch failed: ${err}`),
161
- )
162
-
163
- // From promise
164
- const fetchUser = Task({ name: "UserFetch" }).fromPromise(fetchUserAPI)
165
-
166
- // Usage
167
- syncTask.then((value) => console.log(value)).catch((error) => console.error(error))
168
- ```
169
-
170
- ### Tuple
171
-
172
- ```typescript
173
- // Create: Tuple(...values)
174
- const pair = Tuple(42, "hello")
175
-
176
- // Access: .first(), .second(), etc.
177
- pair.first() // 42
178
- pair.second() // "hello"
179
-
180
- // Transform: .map(), .mapFirst(), .mapSecond()
181
- pair.mapFirst((x) => x * 2) // Tuple(84, "hello")
182
- ```
183
-
184
- ## Common Patterns
185
-
186
- ### Type Safety
187
-
188
- ```typescript
189
- // Branded types
190
- type UserId = Brand<string, "UserId">
191
- const UserId = (id: string): UserId => {
192
- if (!/^U\d{6}$/.test(id)) throw new Error("Invalid ID format")
193
- return id as UserId
194
- }
195
-
196
- // Type-safe functions
197
- function getUserById(id: UserId): User {
198
- /* ... */
199
- }
200
- getUserById(UserId("U123456")) // Works
201
- getUserById("U123456") // Type error
202
- ```
203
-
204
- ### Error Handling
205
-
206
- ```typescript
207
- // Option for nullable values
208
- const maybeUser = Option(findUser(id))
209
- maybeUser.fold(
210
- () => console.log("User not found"),
211
- (user) => console.log("User:", user.name),
212
- )
213
-
214
- // Either for errors with context
215
- const validationResult = validateForm(formData)
216
- validationResult.fold(
217
- (errors) => handleErrors(errors),
218
- (data) => processForm(data),
219
- )
220
-
221
- // Try for exception safety
222
- const parseResult = Try(() => JSON.parse(input))
223
- parseResult.fold(
224
- (err) => console.error("Parse error:", err.message),
225
- (data) => console.log("Data:", data),
226
- )
227
- ```
228
-
229
- ### Chaining Operations
230
-
231
- ```typescript
232
- // Option chain
233
- const userCity = Option(user)
234
- .flatMap((u) => Option(u.address))
235
- .flatMap((a) => Option(a.city))
236
- .getOrElse("Unknown")
237
-
238
- // Either chain
239
- parseInput(input)
240
- .flatMap(validateData)
241
- .flatMap(transformData)
242
- .fold(
243
- (err) => handleError(err),
244
- (result) => displayResult(result),
245
- )
246
-
247
- // List processing
248
- List([1, 2, 3, 4, 5])
249
- .filter((n) => n % 2 === 0)
250
- .map((n) => n * n)
251
- .foldLeft(0)((acc, n) => acc + n) // 20 (4 + 16)
252
- ```
253
-
254
- ### Pattern Matching
255
-
256
- ```typescript
257
- // Using match method
258
- result.match({
259
- Some: (value) => `Found: ${value}`,
260
- None: () => "Not found",
261
- })
262
-
263
- // Using fold method
264
- either.fold(
265
- (left) => `Error: ${left}`,
266
- (right) => `Success: ${right}`,
267
- )
268
-
269
- // Using MatchableUtils
270
- const isPositive = MatchableUtils.when(
271
- (n: number) => n > 0,
272
- (n) => `Positive: ${n}`,
273
- )
274
-
275
- const isNegative = MatchableUtils.when(
276
- (n: number) => n < 0,
277
- (n) => `Negative: ${n}`,
278
- )
279
-
280
- const defaultCase = MatchableUtils.default((n: number) => `Zero: ${n}`)
281
-
282
- // Usage
283
- isPositive(42) ?? isNegative(42) ?? defaultCase(42) // "Positive: 42"
284
- ```
285
-
286
- ### Functional Composition
287
-
288
- ```typescript
289
- // Using pipe for sequential operations
290
- import { pipe } from "functype"
291
-
292
- const result = pipe(
293
- Option(input),
294
- (opt) => opt.map((s) => s.trim()),
295
- (opt) => opt.filter((s) => s.length > 0),
296
- (opt) => opt.map((s) => parseInt(s, 10)),
297
- (opt) => opt.filter((n) => !isNaN(n)),
298
- (opt) => opt.getOrElse(0),
299
- )
300
-
301
- // Converting between types
302
- import { FoldableUtils } from "functype"
303
-
304
- const optionAsList = FoldableUtils.toList(option)
305
- const listAsOption = FoldableUtils.toOption(list)
306
- const tryAsEither = FoldableUtils.toEither(tryVal, "Default error")
307
- ```
308
-
309
- ## Key Principles
310
-
311
- 1. **Immutability**: All data structures return new instances when modified
312
- 2. **Type Safety**: Strong TypeScript typing throughout the library
313
- 3. **Null Safety**: No null/undefined values within containers (Option, Either, etc.)
314
- 4. **Error Handling**: Explicit error handling using functional patterns
315
- 5. **Pattern Matching**: Consistent APIs for inspecting and handling variants
316
- 6. **Composability**: Methods designed for chaining and composition
317
- 7. **Consistency**: Similar patterns across different data structures
318
-
319
- ## Common Imports
320
-
321
- ```typescript
322
- // Full package import (not recommended for production)
323
- import { Option, Either, Try, List } from "functype"
324
-
325
- // Optimized imports for tree-shaking
326
- import { Option } from "functype/option"
327
- import { Either } from "functype/either"
328
- import { List } from "functype/list"
329
-
330
- // Individual constructor imports
331
- import { some, none } from "functype/option"
332
- import { right, left } from "functype/either"
333
- ```
334
-
335
- ## Type Class Hierarchy
336
-
337
- - **Functor**: `map` - Transform values while preserving structure
338
- - **Applicative**: Apply functions inside containers
339
- - **Monad**: `flatMap` - Chain operations that return containerized values
340
- - **Foldable**: `fold`, `foldLeft`, `foldRight` - Collapse structure
341
- - **Traversable**: Convert/sequence containers
342
-
343
- ## Anti-Patterns to Avoid
344
-
345
- 1. ❌ **Unnecessary Unwrapping**:
346
-
347
- ```typescript
348
- // Bad
349
- if (option.isDefined()) {
350
- doSomething(option.get())
351
- } else {
352
- doSomethingElse()
353
- }
354
-
355
- // Good
356
- option.fold(
357
- () => doSomethingElse(),
358
- (value) => doSomething(value),
359
- )
360
- ```
361
-
362
- 2. ❌ **Throwing from Inside Containers**:
363
-
364
- ```typescript
365
- // Bad
366
- option.map((value) => {
367
- if (!isValid(value)) throw new Error("Invalid")
368
- return transform(value)
369
- })
370
-
371
- // Good
372
- option.flatMap((value) => (isValid(value) ? Option(transform(value)) : Option(null)))
373
- ```
374
-
375
- 3. ❌ **Not Using Composition**:
376
-
377
- ```typescript
378
- // Bad
379
- const a = option.map((x) => x + 1)
380
- const b = a.filter((x) => x > 10)
381
- const c = b.getOrElse(0)
382
-
383
- // Good
384
- const result = option
385
- .map((x) => x + 1)
386
- .filter((x) => x > 10)
387
- .getOrElse(0)
388
- ```
389
-
390
- 4. ❌ **Mixing Imperative and Functional Styles**:
391
-
392
- ```typescript
393
- // Bad
394
- let result = 0
395
- option.fold(
396
- () => {
397
- result = 42
398
- },
399
- (value) => {
400
- result = value
401
- },
402
- )
403
-
404
- // Good
405
- const result = option.getOrElse(42)
406
- ```