functype 0.8.67 → 0.8.69

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 (48) hide show
  1. package/README.md +136 -6
  2. package/dist/Either-BfXNbTHo.d.ts +533 -0
  3. package/dist/Map-vivbm5n0.d.ts +65 -0
  4. package/dist/{Tuple-DfdXAbL_.d.ts → Valuable-CtuVEKTZ.d.ts} +17 -10
  5. package/dist/chunk-5DWCHDSA.mjs +39 -0
  6. package/dist/chunk-5DWCHDSA.mjs.map +1 -0
  7. package/dist/chunk-7PQA3W7W.mjs +2 -0
  8. package/dist/chunk-7PQA3W7W.mjs.map +1 -0
  9. package/dist/either/index.d.ts +2 -3
  10. package/dist/either/index.mjs +1 -1
  11. package/dist/fpromise/index.d.ts +373 -3
  12. package/dist/fpromise/index.mjs +1 -1
  13. package/dist/index.d.ts +533 -2
  14. package/dist/index.mjs +1 -1
  15. package/dist/list/index.d.ts +2 -3
  16. package/dist/list/index.mjs +1 -1
  17. package/dist/map/index.d.ts +4 -3
  18. package/dist/map/index.mjs +1 -1
  19. package/dist/option/index.d.ts +2 -987
  20. package/dist/option/index.mjs +1 -1
  21. package/dist/set/index.d.ts +2 -3
  22. package/dist/set/index.mjs +1 -1
  23. package/dist/try/index.d.ts +59 -3
  24. package/dist/try/index.mjs +1 -1
  25. package/dist/tuple/index.d.ts +12 -1
  26. package/dist/tuple/index.mjs +1 -1
  27. package/package.json +17 -16
  28. package/readme/BUNDLE_OPTIMIZATION.md +74 -0
  29. package/readme/FPromise-Assessment.md +43 -0
  30. package/readme/HKT.md +110 -0
  31. package/readme/ROADMAP.md +113 -0
  32. package/readme/TASK-IMPLEMENTATION.md +290 -0
  33. package/readme/TASK-TODO.md +40 -0
  34. package/readme/TASK-UPDATES.md +64 -0
  35. package/readme/TUPLE-EXAMPLES.md +79 -0
  36. package/readme/TaskMigration.md +129 -0
  37. package/readme/ai-guide.md +406 -0
  38. package/readme/examples.md +2093 -0
  39. package/readme/quick-reference.md +514 -0
  40. package/readme/task-cancellation-progress.md +258 -0
  41. package/readme/task-error-handling.md +128 -0
  42. package/readme/task-quick-reference.md +157 -0
  43. package/readme/tasks.md +205 -0
  44. package/readme/type-index.md +238 -0
  45. package/dist/chunk-NTL4HYMA.mjs +0 -18
  46. package/dist/chunk-NTL4HYMA.mjs.map +0 -1
  47. package/dist/chunk-PXFJPCM7.mjs +0 -2
  48. package/dist/chunk-PXFJPCM7.mjs.map +0 -1
@@ -0,0 +1,290 @@
1
+ # Task Implementation Analysis and Best Practices
2
+
3
+ This document provides a deep analysis of the Task implementation in functype, discussing its design considerations, trade-offs, and recommendations for effective usage.
4
+
5
+ ## Overview of Task Implementation
6
+
7
+ The Task module provides a robust bridge between functional programming patterns and asynchronous operations. It offers a structured way to handle errors, cancellation, and progress tracking while maintaining type safety.
8
+
9
+ Key features include:
10
+
11
+ - Named task contexts for richer error information
12
+ - Explicit try/catch/finally semantics
13
+ - Interoperability with Promise-based code
14
+ - Cancellation support
15
+ - Progress tracking for long-running operations
16
+
17
+ ## Advanced Design Considerations
18
+
19
+ ### Error Context Propagation
20
+
21
+ **Current Behavior:**
22
+ When tasks are nested, the outer task's context (name, description) overwrites the inner task's context in error propagation:
23
+
24
+ ```typescript
25
+ // If an error occurs in the inner task:
26
+ await Task({ name: "OuterTask" }).Async(async () => {
27
+ return Task({ name: "InnerTask" }).Async(async () => {
28
+ throw new Error("Inner error")
29
+ })
30
+ })
31
+
32
+ // The error will have:
33
+ // - message: "Inner error"
34
+ // - name: "OuterTask" (not "InnerTask")
35
+ // - taskInfo: { name: "OuterTask", ... }
36
+ ```
37
+
38
+ This happens because when the inner task's promise rejects, it's caught by the outer task, which wraps it in its own error context. This is technically correct from a runtime perspective but might be counterintuitive when debugging.
39
+
40
+ **Recommendation:**
41
+ Consider implementing an option to preserve the innermost error context:
42
+
43
+ ```typescript
44
+ // Possible enhancement
45
+ const preserveErrorContext = true
46
+ await Task({ name: "OuterTask", preserveErrorContext }).Async(...)
47
+
48
+ // Which would yield an error with:
49
+ // - Error context: "InnerTask" (preserved from inner task)
50
+ // - Original context chain: ["OuterTask", "InnerTask"] (for tracing)
51
+ ```
52
+
53
+ ### Asynchronous Edge Cases
54
+
55
+ Some asynchronous patterns can create complexity in error handling, particularly around cancellation and finally blocks:
56
+
57
+ **Potential Issues:**
58
+
59
+ 1. Race conditions between cancellation signals and operation completion
60
+ 2. Callback execution order with finally blocks and cancellation
61
+ 3. Resource cleanup timing in complex async flows
62
+
63
+ **Recommendations:**
64
+
65
+ - Use explicit state machines for complex task flows
66
+ - Implement deterministic callback ordering guarantees
67
+ - Add explicit resource tracking for critical operations
68
+
69
+ ```typescript
70
+ // Structured resource pattern example
71
+ Task.withResource(
72
+ () => openResource(),
73
+ (resource) => useResource(resource),
74
+ (resource) => closeResource(resource),
75
+ )
76
+ ```
77
+
78
+ ### Performance Considerations
79
+
80
+ Task operations add some overhead compared to native Promises:
81
+
82
+ 1. **Extra Promise wrapping** - Each Task operation creates additional Promise layers
83
+ 2. **Error conversion** - Converting to Throwable objects has a small cost
84
+ 3. **Context maintenance** - Task metadata is carried throughout the operation
85
+ 4. **Cancellation checks** - Additional checks during execution
86
+
87
+ **Recommendations:**
88
+
89
+ - Use the Task API selectively for operations where the benefits outweigh costs
90
+ - Consider a lightweight mode for performance-critical paths:
91
+
92
+ ```typescript
93
+ // Hypothetical lightweight mode
94
+ const lightTask = Task.light()
95
+ lightTask.Async(...) // Minimal overhead, fewer features
96
+ ```
97
+
98
+ - Group multiple small tasks into larger task units to amortize overhead
99
+
100
+ ## Cancellation Best Practices
101
+
102
+ The cancellation system is cooperative rather than preemptive, meaning tasks must actively check for cancellation:
103
+
104
+ ### Effective Cancellation Patterns
105
+
106
+ ```typescript
107
+ // 1. Regular checking pattern
108
+ Task.cancellable(async (token) => {
109
+ for (const item of largeDataset) {
110
+ // Check cancellation periodically
111
+ if (token.isCancelled) {
112
+ return // Exit early
113
+ }
114
+
115
+ // Process item
116
+ await processItem(item)
117
+ }
118
+ })
119
+
120
+ // 2. Integration with fetch and DOM APIs
121
+ Task.cancellable(async (token) => {
122
+ const response = await fetch(url, {
123
+ signal: token.signal, // AbortSignal integration
124
+ })
125
+ return await response.json()
126
+ })
127
+
128
+ // 3. Custom cancellation behavior
129
+ Task.cancellable(async (token) => {
130
+ let resources = []
131
+
132
+ token.onCancel(() => {
133
+ // Clean up resources when cancelled
134
+ resources.forEach((r) => r.dispose())
135
+ })
136
+
137
+ // Main task work...
138
+ })
139
+ ```
140
+
141
+ ### Cancellation Caveats
142
+
143
+ 1. **Cancellation is not guaranteed to be immediate** - Tasks may continue briefly after cancellation
144
+ 2. **External resources may need explicit cleanup** - Database connections, file handles, etc.
145
+ 3. **Third-party APIs may not support cancellation** - Wrapping them requires careful handling
146
+
147
+ ## Progress Tracking
148
+
149
+ For long-running operations, progress tracking provides visibility:
150
+
151
+ ```typescript
152
+ // Basic progress usage
153
+ const { task, currentProgress } = Task.withProgress(
154
+ async (updateProgress) => {
155
+ updateProgress(0) // Start
156
+
157
+ // Do work in chunks
158
+ for (let i = 0; i < 10; i++) {
159
+ await doChunk(i)
160
+ updateProgress((i + 1) * 10) // 10%, 20%, etc.
161
+ }
162
+
163
+ return result
164
+ },
165
+ (percent) => {
166
+ // Update UI with progress
167
+ updateProgressBar(percent)
168
+ },
169
+ )
170
+
171
+ // Combined with cancellation
172
+ const { task, cancel, currentProgress } = Task.withProgress(async (updateProgress, token) => {
173
+ // Both progress tracking and cancellation
174
+ })
175
+ ```
176
+
177
+ ### Progress Implementation Considerations
178
+
179
+ 1. **Progress granularity** - Too frequent updates can impact performance
180
+ 2. **Cancellation interaction** - Progress should stop updating when cancelled
181
+ 3. **Indeterminate phases** - Some operations can't report precise progress
182
+
183
+ ## Advanced Task Composition
184
+
185
+ ### Task Racing
186
+
187
+ The `Task.race` functionality allows racing multiple tasks against each other with optional timeout:
188
+
189
+ ```typescript
190
+ // Race with timeout
191
+ const raceResult = await Task.race([slowOperation(), fastOperation()], 1000) // 1 second timeout
192
+ ```
193
+
194
+ ### Potential Future Composition Enhancements
195
+
196
+ 1. **Structured Concurrency**
197
+
198
+ ```typescript
199
+ // Hypothetical API
200
+ const { results, errors } = await Task.scope(async (scope) => {
201
+ // All tasks in scope have linked lifecycle
202
+ const task1 = scope.spawn(operation1())
203
+ const task2 = scope.spawn(operation2())
204
+
205
+ return await scope.join() // Wait for all to complete or fail
206
+ })
207
+ ```
208
+
209
+ 2. **Resource Management**
210
+
211
+ ```typescript
212
+ // Hypothetical API for guaranteed resource cleanup
213
+ await Task.using(
214
+ () => openDatabase(), // Acquire
215
+ async (db) => {
216
+ // Use resource
217
+ return await db.query()
218
+ },
219
+ (db) => db.close(), // Always called
220
+ )
221
+ ```
222
+
223
+ ## Testing Considerations
224
+
225
+ Testing Task-based code requires special attention:
226
+
227
+ 1. **Time and async flow control** - Use timeouts and explicit resolutions
228
+ 2. **Cancellation testing** - Test both normal and cancelled paths
229
+ 3. **Progress testing** - Verify progress reporting accuracy
230
+ 4. **Error context verification** - Check error details are preserved
231
+
232
+ Example property tests:
233
+
234
+ ```typescript
235
+ // Task Async should satisfy monad laws
236
+ test("Right identity: t.Async(f) >>= id = t.Async(f)", () => {
237
+ fc.assert(
238
+ fc.property(fc.string(), async (value) => {
239
+ const f = async () => value
240
+ const taskResult = await Task().Async(f)
241
+ const directResult = await f()
242
+ return taskResult === directResult
243
+ }),
244
+ )
245
+ })
246
+ ```
247
+
248
+ ## Integration with Other Patterns
249
+
250
+ Tasks work especially well when combined with other functional patterns:
251
+
252
+ ### With Option
253
+
254
+ ```typescript
255
+ // Convert nullable API response to Option
256
+ const getUserOption = async (id: string) => {
257
+ const response = await Task().Async(async () => {
258
+ return fetch(`/api/users/${id}`)
259
+ })
260
+
261
+ return Option.fromNullable(response)
262
+ }
263
+ ```
264
+
265
+ ### With Either
266
+
267
+ ```typescript
268
+ // Type-specific error handling
269
+ const result = await Task().Async(async () => {
270
+ // Operation returning Either<ApiError, UserData>
271
+ })
272
+
273
+ // Handle specific error types
274
+ result.match({
275
+ left: (error) => handleApiError(error),
276
+ right: (data) => useData(data),
277
+ })
278
+ ```
279
+
280
+ ## Conclusion
281
+
282
+ The Task implementation offers a powerful approach to functional asynchronous programming. By understanding its design trade-offs and following best practices, developers can create more robust, maintainable code with better error handling.
283
+
284
+ Remember that Task is not a replacement for all Promise usage - evaluate when the additional features justify the slightly increased complexity and overhead.
285
+
286
+ ## See Also
287
+
288
+ - [Task Error Handling](../docs/task-error-handling.md)
289
+ - [Task Migration Guide](../docs/TaskMigration.md)
290
+ - [Task TODO](../docs/TASK-TODO.md)
@@ -0,0 +1,40 @@
1
+ # Task TODO
2
+
3
+ ## Goals
4
+
5
+ - Enhance the Task module as an adapter between promise-based code and functional patterns
6
+ - Improve interoperability with existing JavaScript/TypeScript codebases
7
+ - Allow gradual migration to functional patterns without complete rewrites
8
+
9
+ ## Implementation Tasks
10
+
11
+ - [x] Review current Task implementation for completeness of promise integration
12
+ - [x] Ensure robust error handling in sync/async conversions
13
+ - [x] Document explicit try/catch/finally semantics
14
+ - [x] Add examples showing migration from promise-based to functional patterns
15
+ - [x] Add utilities to simplify Task composition with promise-returning functions
16
+ - [x] Create migration guide for converting promise chains to Task operations
17
+ - [x] Create Task.race for racing multiple tasks with timeout support
18
+ - [x] Implement Task.fromNodeCallback for Node.js style callbacks
19
+ - [x] Implement cancellation support for Task operations
20
+ - [x] Add progress tracking for long-running Task operations
21
+
22
+ ## Design Considerations
23
+
24
+ - Maintain clear separation between synchronous and promise-based operations
25
+ - Preserve functional error handling patterns while supporting promise interop
26
+ - Keep API consistent with the rest of the library's functional approach
27
+
28
+ ## Completed Enhancements
29
+
30
+ - Added `fromPromise` adapter to convert promise-returning functions to Task-compatible functions
31
+ - Added `toPromise` converter to transform Task results back to promises
32
+ - Enhanced documentation with clearer descriptions of functionality
33
+ - Created TaskMigration.md guide showing how to migrate from promises to functional Task patterns
34
+ - Added comprehensive tests for the new adapter methods
35
+ - Implemented `Task.race` for racing multiple tasks with timeout support
36
+ - Added `Task.fromNodeCallback` for Node.js-style callback integration
37
+ - Implemented cancellation support with CancellationToken pattern
38
+ - Added progress tracking for long-running operations
39
+ - Created property-based tests verifying monadic laws and edge cases
40
+ - Added comprehensive documentation for all new functionality
@@ -0,0 +1,64 @@
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.
@@ -0,0 +1,79 @@
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
+
67
+ - When you need to store different types in a fixed structure
68
+ - When you want type safety beyond what arrays provide
69
+
70
+ 2. **APIs returning fixed-length, mixed-type results**:
71
+
72
+ - When a function returns multiple values of different types
73
+
74
+ 3. **Data transformation pipelines**:
75
+
76
+ - When you need to transform data while preserving type information
77
+
78
+ 4. **Configuration objects with fixed format**:
79
+ - When config must follow a specific format with specific types at each position
@@ -0,0 +1,129 @@
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