@typed/async-data 0.13.0 → 1.0.0-beta.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 +159 -0
- package/dist/index.d.ts +92 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +169 -5
- package/package.json +18 -28
- package/src/AsyncData.test.ts +417 -62
- package/src/index.test.ts +497 -0
- package/src/index.ts +291 -4
- package/tsconfig.json +5 -26
- package/.nvmrc +0 -1
- package/biome.json +0 -36
- package/dist/AsyncData.d.ts +0 -196
- package/dist/AsyncData.js +0 -285
- package/dist/AsyncData.js.map +0 -1
- package/dist/LazyRef.d.ts +0 -21
- package/dist/LazyRef.js +0 -27
- package/dist/LazyRef.js.map +0 -1
- package/dist/Progress.d.ts +0 -25
- package/dist/Progress.js +0 -21
- package/dist/Progress.js.map +0 -1
- package/dist/TypeId.d.ts +0 -11
- package/dist/TypeId.js +0 -8
- package/dist/TypeId.js.map +0 -1
- package/dist/_internal.d.ts +0 -16
- package/dist/_internal.js +0 -53
- package/dist/_internal.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/readme.md +0 -218
- package/src/AsyncData.ts +0 -654
- package/src/LazyRef.ts +0 -87
- package/src/Progress.ts +0 -33
- package/src/TypeId.ts +0 -13
- package/src/_internal.ts +0 -114
package/readme.md
DELETED
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
# @typed/async-data
|
|
2
|
-
|
|
3
|
-
A type-safe, Effect-based library for managing asynchronous data states in TypeScript applications. Built on top of the Effect ecosystem, it provides a powerful and composable way to handle loading, success, failure, and optimistic states of your data.
|
|
4
|
-
|
|
5
|
-
Key benefits:
|
|
6
|
-
- 🎯 **Type-safe**: Full TypeScript support with strict typing
|
|
7
|
-
- 🔄 **Effect Integration**: Seamless integration with the Effect ecosystem
|
|
8
|
-
- 📊 **Progress Tracking**: Built-in support for loading progress
|
|
9
|
-
- 🎭 **State Management**: Comprehensive state handling for async operations
|
|
10
|
-
- 🔄 **Optimistic Updates**: First-class support for optimistic UI updates
|
|
11
|
-
- 🛡️ **Error Handling**: Type-safe error handling with Effect
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install @typed/async-data
|
|
17
|
-
# or
|
|
18
|
-
pnpm add @typed/async-data
|
|
19
|
-
# or
|
|
20
|
-
yarn add @typed/async-data
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Basic Usage
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
import * as AsyncData from '@typed/async-data'
|
|
27
|
-
import { Effect } from 'effect'
|
|
28
|
-
|
|
29
|
-
// Create an AsyncData instance
|
|
30
|
-
const noData = AsyncData.noData()
|
|
31
|
-
const loading = AsyncData.loading()
|
|
32
|
-
const success = AsyncData.success(1)
|
|
33
|
-
const failure = AsyncData.failure(Cause.fail('error'))
|
|
34
|
-
const refreshing = AsyncData.refreshing(AsyncData.success(1))
|
|
35
|
-
const optimistic = AsyncData.optimistic(AsyncData.loading(), 1)
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Core Features
|
|
39
|
-
|
|
40
|
-
### State Types
|
|
41
|
-
|
|
42
|
-
AsyncData represents data that can be in one of six states:
|
|
43
|
-
|
|
44
|
-
1. `NoData` - Initial state when no data has been loaded
|
|
45
|
-
2. `Loading` - Data is being loaded for the first time
|
|
46
|
-
3. `Success<A>` - Successfully loaded data of type A
|
|
47
|
-
4. `Failure<E>` - Failed to load data with error of type E
|
|
48
|
-
5. `Refreshing<A, E>` - Reloading data while preserving previous state
|
|
49
|
-
6. `Optimistic<A, E>` - Optimistically updated while waiting for confirmation
|
|
50
|
-
|
|
51
|
-
### Effect Integration
|
|
52
|
-
|
|
53
|
-
AsyncData instances are Effect values, allowing seamless integration with Effect's ecosystem:
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
import { Effect, Cause } from 'effect'
|
|
57
|
-
import * as AsyncData from '@typed/async-data'
|
|
58
|
-
|
|
59
|
-
const program = Effect.gen(function* (_) {
|
|
60
|
-
// NoData and Loading are Failures
|
|
61
|
-
const noData = AsyncData.noData()
|
|
62
|
-
const noDataExit = yield* Effect.exit(noData)
|
|
63
|
-
// noDataExit === Exit.fail(noData)
|
|
64
|
-
|
|
65
|
-
// Success values are Successes
|
|
66
|
-
const success = AsyncData.success(1)
|
|
67
|
-
const value = yield* success
|
|
68
|
-
// value === 1
|
|
69
|
-
|
|
70
|
-
// Refreshing preserves the previous state
|
|
71
|
-
const refreshing = AsyncData.refreshing(AsyncData.success(1))
|
|
72
|
-
const refreshValue = yield* refreshing
|
|
73
|
-
// refreshValue === 1
|
|
74
|
-
|
|
75
|
-
// Optimistic updates provide immediate feedback
|
|
76
|
-
const optimistic = AsyncData.optimistic(AsyncData.fail('not used'), 1)
|
|
77
|
-
const optValue = yield* optimistic
|
|
78
|
-
// optValue === 1
|
|
79
|
-
})
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### LazyRef Integration
|
|
83
|
-
|
|
84
|
-
AsyncData can be used with LazyRef for managing state over time:
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
import { Effect, Schema } from 'effect'
|
|
88
|
-
import * as AsyncData from '@typed/async-data'
|
|
89
|
-
|
|
90
|
-
// Define a schema-based AsyncData type
|
|
91
|
-
class Example extends AsyncData.AsyncData({
|
|
92
|
-
success: Schema.Number,
|
|
93
|
-
failure: Schema.String,
|
|
94
|
-
}) {}
|
|
95
|
-
|
|
96
|
-
const program = Effect.gen(function* (_) {
|
|
97
|
-
// Create a lazy reference
|
|
98
|
-
const example = yield* AsyncData.lazyRef(Example)
|
|
99
|
-
|
|
100
|
-
// Run an async operation
|
|
101
|
-
yield* Effect.forkScoped(
|
|
102
|
-
AsyncData.runEffect(
|
|
103
|
-
example,
|
|
104
|
-
Effect.delay(Effect.succeed(1), 500)
|
|
105
|
-
)
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
// State transitions automatically
|
|
109
|
-
const initial = yield* example
|
|
110
|
-
// initial === Example.noData()
|
|
111
|
-
|
|
112
|
-
yield* TestClock.adjust(1)
|
|
113
|
-
const loading = yield* example
|
|
114
|
-
// loading === Example.loading()
|
|
115
|
-
|
|
116
|
-
yield* TestClock.adjust(500)
|
|
117
|
-
const final = yield* example
|
|
118
|
-
// final === Example.success(1)
|
|
119
|
-
})
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Progress Tracking
|
|
123
|
-
|
|
124
|
-
AsyncData includes built-in support for tracking loading progress:
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
import * as AsyncData from '@typed/async-data'
|
|
128
|
-
import { Progress } from '@typed/async-data'
|
|
129
|
-
|
|
130
|
-
// Create loading state with progress
|
|
131
|
-
const progress = Progress.make({
|
|
132
|
-
loaded: 50,
|
|
133
|
-
total: Option.some(100)
|
|
134
|
-
})
|
|
135
|
-
const loading = AsyncData.loading(progress)
|
|
136
|
-
|
|
137
|
-
// Update progress
|
|
138
|
-
const updated = AsyncData.updateProgress(loading,
|
|
139
|
-
Progress.make({ loaded: 75, total: Option.some(100) })
|
|
140
|
-
)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Pattern Matching
|
|
144
|
-
|
|
145
|
-
AsyncData provides comprehensive pattern matching capabilities:
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import * as AsyncData from '@typed/async-data'
|
|
149
|
-
|
|
150
|
-
const result = AsyncData.match(data, {
|
|
151
|
-
NoData: () => 'No data yet',
|
|
152
|
-
Loading: (progress) => `Loading... ${progress}`,
|
|
153
|
-
Success: (value, { isRefreshing, isOptimistic }) =>
|
|
154
|
-
`Value: ${value} ${isRefreshing ? '(refreshing)' : ''} ${isOptimistic ? '(optimistic)' : ''}`,
|
|
155
|
-
Failure: (cause, { isRefreshing }) =>
|
|
156
|
-
`Error: ${cause} ${isRefreshing ? '(refreshing)' : ''}`
|
|
157
|
-
})
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Advanced Usage
|
|
161
|
-
|
|
162
|
-
### Tagged Services
|
|
163
|
-
|
|
164
|
-
Create tagged services with AsyncData:
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
import * as AsyncData from '@typed/async-data'
|
|
168
|
-
import { Effect, Schema } from 'effect'
|
|
169
|
-
|
|
170
|
-
const UserService = AsyncData.Tag('UserService')<
|
|
171
|
-
typeof UserService,
|
|
172
|
-
User,
|
|
173
|
-
string
|
|
174
|
-
>()
|
|
175
|
-
|
|
176
|
-
const program = Effect.gen(function* (_) {
|
|
177
|
-
const users = yield* UserService
|
|
178
|
-
|
|
179
|
-
// Run effects and automatically manage state
|
|
180
|
-
yield* UserService.run(
|
|
181
|
-
Effect.succeed({ id: 1, name: 'John' })
|
|
182
|
-
)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// Provide implementation
|
|
186
|
-
program.pipe(
|
|
187
|
-
Effect.provide(UserService.Default)
|
|
188
|
-
)
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Type-safe Error Handling
|
|
192
|
-
|
|
193
|
-
AsyncData ensures type-safe error handling:
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
import * as AsyncData from '@typed/async-data'
|
|
197
|
-
import { Effect, Cause } from 'effect'
|
|
198
|
-
|
|
199
|
-
type ApiError = { code: number; message: string }
|
|
200
|
-
|
|
201
|
-
const result = AsyncData.failure<ApiError>(
|
|
202
|
-
Cause.fail({ code: 404, message: 'Not found' })
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
AsyncData.match(result, {
|
|
206
|
-
Failure: (cause) => {
|
|
207
|
-
// cause is typed as Cause<ApiError>
|
|
208
|
-
const errors = Array.from(Cause.failures(cause))
|
|
209
|
-
// Handle errors
|
|
210
|
-
},
|
|
211
|
-
// ... other cases
|
|
212
|
-
})
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## License
|
|
216
|
-
|
|
217
|
-
MIT
|
|
218
|
-
|