@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/src/AsyncData.ts DELETED
@@ -1,654 +0,0 @@
1
- import {
2
- Cause,
3
- Effect,
4
- Either,
5
- Equal,
6
- Equivalence,
7
- Exit,
8
- identity,
9
- Option,
10
- Schema,
11
- SchemaAST,
12
- Unify,
13
- } from 'effect'
14
- import { dual } from 'effect/Function'
15
- import { Progress, type ProgressEncoded } from './Progress.js'
16
- import { DataEffect, LiteralWithDefault } from './_internal.js'
17
-
18
- export type AsyncData<A, E = never> =
19
- | NoData
20
- | Loading
21
- | Success<A>
22
- | Failure<E>
23
- | Refreshing<A, E>
24
- | Optimistic<A, E>
25
-
26
- export namespace AsyncData {
27
- export type Encoded<A, E = never> =
28
- | typeof NoData.Encoded
29
- | typeof Loading.Encoded
30
- | SuccessEncoded<A>
31
- | FailureEncoded<E>
32
- | RefreshingEncoded<A, E>
33
- | OptimisticEncoded<A, E>
34
- export interface SuccessEncoded<A> {
35
- readonly _tag: 'Success'
36
- readonly value: A
37
- }
38
-
39
- export interface FailureEncoded<E> {
40
- readonly _tag: 'Failure'
41
- readonly cause: Schema.CauseEncoded<E, unknown>
42
- }
43
-
44
- export type RefreshingEncoded<A, E = never> = {
45
- readonly _tag: 'Refreshing'
46
- readonly previous: SuccessEncoded<A> | FailureEncoded<E>
47
- readonly progress?: ProgressEncoded
48
- }
49
-
50
- export interface OptimisticEncoded<A, E = never> {
51
- readonly _tag: 'Optimistic'
52
- readonly previous: Encoded<A, E>
53
- readonly value: A
54
- }
55
-
56
- /**
57
- * @category models
58
- * @since 1.0.0
59
- */
60
- export interface Unify<A extends { [Unify.typeSymbol]?: any }> extends Effect.EffectUnify<A> {
61
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
62
- AsyncData: () => Unify_<A[Unify.typeSymbol]> extends AsyncData<infer E0, infer A0> | infer _
63
- ? AsyncData<E0, A0>
64
- : never
65
- }
66
-
67
- type Unify_<T extends AsyncData<any, any>> = T extends NoData
68
- ? AsyncData<never, never>
69
- : T extends Loading
70
- ? AsyncData<never, never>
71
- : T extends Failure<infer E>
72
- ? AsyncData<E, never>
73
- : T extends Success<infer A>
74
- ? AsyncData<never, A>
75
- : T extends Optimistic<infer A, infer E>
76
- ? AsyncData<A, E>
77
- : T extends Refreshing<infer A, infer E>
78
- ? AsyncData<A, E>
79
- : never
80
-
81
- /**
82
- * @category models
83
- * @since 1.0.0
84
- */
85
- export interface IgnoreList extends Effect.EffectUnifyIgnore {
86
- Effect: true
87
- }
88
- }
89
-
90
- export class NoData
91
- extends Schema.TaggedError<NoData>()('NoData', {})
92
- implements Effect.Effect<never, NoData, never> {}
93
-
94
- export const noData: {
95
- (): NoData
96
- <A, E = never>(): AsyncData<A, E>
97
- } = () => NoData.make()
98
-
99
- export class Loading
100
- extends Schema.TaggedError<Loading>()('Loading', {
101
- progress: Schema.optionalWith(Progress, { as: 'Option', default: undefined }),
102
- })
103
- implements Effect.Effect<never, Loading, never> {}
104
-
105
- export function loading(progress?: Progress): Loading
106
- export function loading<A, E = never>(progress?: Progress): AsyncData<A, E>
107
- export function loading<A, E = never>(progress?: Progress): AsyncData<A, E> {
108
- return Loading.make({ progress: Option.fromNullable(progress) })
109
- }
110
-
111
- export class Success<A>
112
- extends DataEffect('Success')<{ readonly value: A }, A>
113
- implements Effect.Effect<A>
114
- {
115
- constructor(value: A) {
116
- super({ value }, Effect.succeed(value))
117
- }
118
-
119
- static schema<A, I, R>(
120
- value: Schema.Schema<A, I, R>,
121
- ): Schema.SchemaClass<Success<A>, AsyncData.SuccessEncoded<I>, R> {
122
- return Schema.Struct({
123
- _tag: LiteralWithDefault<'_tag'>()('Success'),
124
- value,
125
- }).pipe(
126
- Schema.transform(Schema.instanceOf(Success<A>), {
127
- strict: true,
128
- decode: (from) => new Success(from.value),
129
- encode: identity,
130
- }),
131
- )
132
- }
133
- }
134
-
135
- export function success<A>(value: A): Success<A>
136
- export function success<A, E = never>(value: A): AsyncData<A, E>
137
- export function success<A>(value: A): Success<A> {
138
- return new Success(value)
139
- }
140
-
141
- export class Failure<E>
142
- extends DataEffect('Failure')<{ readonly cause: Cause.Cause<E> }, never, E, never>
143
- implements Effect.Effect<never, E, never>
144
- {
145
- constructor(cause: Cause.Cause<E>) {
146
- super({ cause }, Effect.failCause(cause))
147
- }
148
-
149
- static schema<E, I, R>(
150
- error: Schema.Schema<E, I, R>,
151
- ): Schema.SchemaClass<Failure<E>, AsyncData.FailureEncoded<I>, R> {
152
- return Schema.Struct({
153
- _tag: LiteralWithDefault<'_tag'>()('Failure'),
154
- cause: Schema.Cause({
155
- error,
156
- defect: Schema.Unknown,
157
- }),
158
- }).pipe(
159
- Schema.transform(Schema.instanceOf(Failure<E>), {
160
- strict: true,
161
- decode: (from) => new Failure(from.cause),
162
- encode: identity,
163
- }),
164
- )
165
- }
166
- }
167
-
168
- export function failure<E>(cause: Cause.Cause<E>): Failure<E>
169
- export function failure<E, A = never>(cause: Cause.Cause<E>): AsyncData<A, E>
170
- export function failure<E>(cause: Cause.Cause<E>): Failure<E> {
171
- return new Failure(cause)
172
- }
173
-
174
- export function die(cause: unknown): Failure<never>
175
- export function die<A, E = never>(cause: unknown): AsyncData<A, E>
176
- export function die<E>(cause: unknown): Failure<E> {
177
- return new Failure(Cause.die(cause))
178
- }
179
-
180
- export function fail<E>(error: E): Failure<E> {
181
- return new Failure(Cause.fail(error))
182
- }
183
-
184
- export class Refreshing<A, E>
185
- extends DataEffect('Refreshing')<
186
- { readonly previous: Success<A> | Failure<E>; readonly progress: Option.Option<Progress> },
187
- A,
188
- E,
189
- never
190
- >
191
- implements Effect.Effect<A, E>
192
- {
193
- constructor(previous: Success<A> | Failure<E>, progress: Option.Option<Progress>) {
194
- super({ previous, progress }, previous)
195
- }
196
-
197
- static schema<A, EI, E, AI, R>(
198
- previous: Schema.Schema<
199
- Success<A> | Failure<E>,
200
- AsyncData.SuccessEncoded<AI> | AsyncData.FailureEncoded<EI>,
201
- R
202
- >,
203
- ): Schema.SchemaClass<Refreshing<A, E>, AsyncData.RefreshingEncoded<AI, EI>, R> {
204
- return Schema.Struct({
205
- _tag: LiteralWithDefault<'_tag'>()('Refreshing'),
206
- previous,
207
- progress: Schema.optionalWith(Progress, { as: 'Option', default: undefined }),
208
- }).pipe(
209
- Schema.transform(Schema.instanceOf(Refreshing<A, E>), {
210
- strict: true,
211
- decode: (from) => new Refreshing(from.previous, from.progress),
212
- encode: identity,
213
- }),
214
- )
215
- }
216
- }
217
-
218
- export function refreshing<A = never, E = never>(
219
- previous: Success<A> | Failure<E>,
220
- progress?: Progress,
221
- ): Refreshing<A, E> {
222
- return new Refreshing(previous, Option.fromNullable(progress))
223
- }
224
-
225
- export class Optimistic<A, E>
226
- extends DataEffect('Optimistic')<{ readonly previous: AsyncData<A, E>; readonly value: A }, A>
227
- implements Effect.Effect<A>
228
- {
229
- constructor(previous: AsyncData<A, E>, value: A) {
230
- super({ previous, value }, Effect.succeed(value))
231
- }
232
-
233
- static schema<A, EI, E, AI, R, R2>(
234
- previous: Schema.Schema<AsyncData<A, E>, AsyncData.Encoded<AI, EI>, R>,
235
- value: Schema.Schema<A, AI, R2>,
236
- ): Schema.SchemaClass<Optimistic<A, E>, AsyncData.OptimisticEncoded<AI, EI>, R | R2> {
237
- return Schema.Struct({
238
- _tag: LiteralWithDefault<'_tag'>()('Optimistic'),
239
- previous,
240
- value,
241
- }).pipe(
242
- Schema.transform(Schema.instanceOf(Optimistic<A, E>), {
243
- strict: true,
244
- decode: (from) => new Optimistic(from.previous, from.value),
245
- encode: identity,
246
- }),
247
- )
248
- }
249
- }
250
-
251
- export const optimistic: {
252
- <A>(value: A): <E>(previous: AsyncData<A, E>) => Optimistic<A, E>
253
- <A, E>(previous: AsyncData<A, E>, value: A): Optimistic<A, E>
254
- } = dual(2, function optimistic<A, E>(previous: AsyncData<A, E>, value: A): Optimistic<A, E> {
255
- return new Optimistic(previous, value)
256
- })
257
-
258
- export const matchAll: {
259
- <A, E, R1, R2, R3, R4, R5, R6>(
260
- data: AsyncData<A, E>,
261
- matchers: {
262
- readonly NoData: () => R1
263
- readonly Loading: (progress: Option.Option<Progress>) => R2
264
- readonly Success: (value: A) => R3
265
- readonly Failure: (cause: Cause.Cause<E>) => R4
266
- readonly Refreshing: (
267
- previous: Success<A> | Failure<E>,
268
- progress: Option.Option<Progress>,
269
- ) => R5
270
- readonly Optimistic: (value: A, previous: AsyncData<A, E>) => R6
271
- },
272
- ): R1 | R2 | R3 | R4 | R5 | R6
273
-
274
- <A, E, R1, R2, R3, R4, R5, R6>(
275
- data: AsyncData<A, E>,
276
- matchers: {
277
- readonly NoData: () => R1
278
- readonly Loading: (progress: Option.Option<Progress>) => R2
279
- readonly Success: (value: A) => R3
280
- readonly Failure: (cause: Cause.Cause<E>) => R4
281
- readonly Refreshing: (
282
- previous: Success<A> | Failure<E>,
283
- progress: Option.Option<Progress>,
284
- ) => R5
285
- readonly Optimistic: (value: A, previous: AsyncData<A, E>) => R6
286
- },
287
- ): R1 | R2 | R3 | R4 | R5 | R6
288
- } = dual(
289
- 2,
290
- function matchAll<A, E, R1, R2, R3, R4, R5, R6>(
291
- data: AsyncData<A, E>,
292
- matchers: {
293
- readonly NoData: () => R1
294
- readonly Loading: (progress: Option.Option<Progress>) => R2
295
- readonly Success: (value: A) => R3
296
- readonly Failure: (cause: Cause.Cause<E>) => R4
297
- readonly Refreshing: (
298
- previous: Success<A> | Failure<E>,
299
- progress: Option.Option<Progress>,
300
- ) => R5
301
- readonly Optimistic: (value: A, previous: AsyncData<A, E>) => R6
302
- },
303
- ): R1 | R2 | R3 | R4 | R5 | R6 {
304
- switch (data._tag) {
305
- case 'NoData':
306
- return matchers.NoData()
307
- case 'Loading':
308
- return matchers.Loading(data.progress)
309
- case 'Success':
310
- return matchers.Success(data.value)
311
- case 'Failure':
312
- return matchers.Failure(data.cause)
313
- case 'Refreshing':
314
- return matchers.Refreshing(data.previous, data.progress)
315
- case 'Optimistic':
316
- return matchers.Optimistic(data.value, data.previous)
317
- }
318
- },
319
- )
320
-
321
- export const match: {
322
- <A, E, R1, R2, R3, R4>(matchers: {
323
- readonly NoData: () => R1
324
- readonly Loading: (progress: Option.Option<Progress>) => R2
325
- readonly Success: (
326
- value: A,
327
- params: {
328
- readonly isRefreshing: boolean
329
- readonly isOptimistic: boolean
330
- readonly progress: Option.Option<Progress>
331
- },
332
- ) => R3
333
- readonly Failure: (
334
- cause: Cause.Cause<E>,
335
- params: { readonly isRefreshing: boolean; readonly progress: Option.Option<Progress> },
336
- ) => R4
337
- }): (data: AsyncData<A, E>) => Unify.Unify<R1 | R2 | R3 | R4>
338
-
339
- <A, E, R1, R2, R3, R4>(
340
- data: AsyncData<A, E>,
341
- matchers: {
342
- readonly NoData: () => R1
343
- readonly Loading: (progress: Option.Option<Progress>) => R2
344
- readonly Success: (
345
- value: A,
346
- params: {
347
- readonly isRefreshing: boolean
348
- readonly isOptimistic: boolean
349
- readonly progress: Option.Option<Progress>
350
- },
351
- ) => R3
352
- readonly Failure: (
353
- cause: Cause.Cause<E>,
354
- params: { readonly isRefreshing: boolean; readonly progress: Option.Option<Progress> },
355
- ) => R4
356
- },
357
- ): Unify.Unify<R1 | R2 | R3 | R4>
358
- } = dual(
359
- 2,
360
- function match<A, E, R1, R2, R3, R4>(
361
- data: AsyncData<A, E>,
362
- matchers: {
363
- readonly NoData: () => R1
364
- readonly Loading: (progress: Option.Option<Progress>) => R2
365
- readonly Success: (
366
- value: A,
367
- params: {
368
- readonly isRefreshing: boolean
369
- readonly isOptimistic: boolean
370
- readonly progress: Option.Option<Progress>
371
- },
372
- ) => R3
373
- readonly Failure: (
374
- cause: Cause.Cause<E>,
375
- params: { readonly isRefreshing: boolean; readonly progress: Option.Option<Progress> },
376
- ) => R4
377
- },
378
- ): Unify.Unify<R1 | R2 | R3 | R4> {
379
- const match_ = (
380
- data: AsyncData<A, E>,
381
- params: {
382
- readonly isRefreshing: boolean
383
- readonly isOptimistic: boolean
384
- readonly progress: Option.Option<Progress>
385
- },
386
- ): R1 | R2 | R3 | R4 =>
387
- matchAll(data, {
388
- NoData: matchers.NoData,
389
- Loading: matchers.Loading,
390
- Success: (value) => matchers.Success(value, params),
391
- Failure: (cause) => matchers.Failure(cause, params),
392
- Refreshing: (previous, progress) =>
393
- match_(previous, { ...params, isRefreshing: true, progress }),
394
- Optimistic: (value) => matchers.Success(value, { ...params, isOptimistic: true }),
395
- })
396
-
397
- return Unify.unify(
398
- match_(data, {
399
- isRefreshing: false,
400
- isOptimistic: false,
401
- progress: Option.none(),
402
- }),
403
- )
404
- },
405
- )
406
-
407
- export function startLoading<A, E>(data: AsyncData<A, E>, progress?: Progress): AsyncData<A, E> {
408
- switch (data._tag) {
409
- case 'Success':
410
- case 'Failure':
411
- return refreshing(data, progress)
412
- case 'NoData':
413
- return loading(progress)
414
- case 'Optimistic':
415
- return optimistic(startLoading(data.previous, progress), data.value)
416
- default:
417
- return data
418
- }
419
- }
420
-
421
- export function stopLoading<A, E>(data: AsyncData<A, E>): AsyncData<A, E> {
422
- switch (data._tag) {
423
- case 'Refreshing':
424
- return data.previous
425
- case 'Loading':
426
- return noData()
427
- case 'Optimistic':
428
- return optimistic(stopLoading(data.previous), data.value)
429
- default:
430
- return data
431
- }
432
- }
433
-
434
- export function updateProgress<A, E>(data: AsyncData<A, E>, progress: Progress): AsyncData<A, E> {
435
- switch (data._tag) {
436
- case 'Refreshing':
437
- return refreshing(data.previous, progress)
438
- case 'Loading':
439
- return loading(progress)
440
- case 'Optimistic':
441
- return optimistic(updateProgress(data.previous, progress), data.value)
442
- default:
443
- return data
444
- }
445
- }
446
-
447
- export interface AsyncDataSchemaClass<E, EI, ER, A, AI, AR>
448
- extends Schema.SchemaClass<AsyncData<A, E>, AsyncData.Encoded<AI, EI>, AR | ER> {
449
- readonly eq: Equivalence.Equivalence<AsyncData<A, E>>
450
-
451
- readonly success: (value: A) => AsyncData<A, E>
452
- readonly failCause: (cause: Cause.Cause<E>) => AsyncData<A, E>
453
- readonly fail: (error: E) => AsyncData<A, E>
454
- readonly die: (cause: unknown) => AsyncData<A, E>
455
- readonly optimistic: (previous: AsyncData<A, E>, value: A) => AsyncData<A, E>
456
- readonly refreshing: (previous: Success<A> | Failure<E>, progress?: Progress) => AsyncData<A, E>
457
- readonly loading: (progress?: Progress) => AsyncData<A, E>
458
- readonly noData: () => AsyncData<A, E>
459
- }
460
-
461
- export function AsyncData<A, AI, AR, E, EI, ER>(
462
- schemas: {
463
- readonly success: Schema.Schema<A, AI, AR>
464
- readonly failure: Schema.Schema<E, EI, ER>
465
- },
466
- annotations?: Schema.Annotations.Schema<AsyncData<A, E>>,
467
- ): AsyncDataSchemaClass<E, EI, ER, A, AI, AR> {
468
- const identifier = Option.all({
469
- E: getIdentifier(schemas.failure.ast),
470
- A: getIdentifier(schemas.success.ast),
471
- }).pipe(
472
- Option.match({
473
- onNone: () => 'AsyncData',
474
- onSome: ({ E, A }) => `AsyncData<${E}, ${A}>`,
475
- }),
476
- )
477
-
478
- const equivalence = makeEquivalence(
479
- Schema.equivalence(schemas.success),
480
- Schema.equivalence(schemas.failure),
481
- )
482
-
483
- const recursive: Schema.Schema<
484
- AsyncData<A, E>,
485
- AsyncData.Encoded<AI, EI>,
486
- AR | ER
487
- > = Schema.suspend(() => AsyncData).annotations({
488
- identifier,
489
- equivalence: () => equivalence,
490
- ...annotations,
491
- })
492
-
493
- const successAndFailure = Schema.Union(
494
- Success.schema(schemas.success),
495
- Failure.schema(schemas.failure),
496
- )
497
-
498
- const AsyncData = Schema.Union(
499
- NoData,
500
- Loading,
501
- successAndFailure,
502
- Refreshing.schema(successAndFailure),
503
- Optimistic.schema(recursive, schemas.success),
504
- ).annotations({
505
- equivalence: () => equivalence,
506
- })
507
-
508
- return class extends AsyncData {
509
- static readonly eq = equivalence
510
- static readonly success = success
511
- static readonly failCause = failure
512
- static readonly fail = fail
513
- static readonly die = die
514
- static readonly optimistic = optimistic
515
- static readonly refreshing = refreshing
516
- static readonly loading = loading
517
- static readonly noData = noData
518
- }
519
- }
520
-
521
- function getIdentifier(ast: SchemaAST.AST) {
522
- return SchemaAST.getJSONIdentifier(ast).pipe(
523
- Option.orElse(() => SchemaAST.getTitleAnnotation(ast)),
524
- )
525
- }
526
-
527
- export function fromExit<A, E>(exit: Exit.Exit<A, E>): AsyncData<A, E> {
528
- return Exit.match(exit, { onSuccess: success<A>, onFailure: failure<E> })
529
- }
530
-
531
- export function fromEither<A, E>(either: Either.Either<A, E>): AsyncData<A, E> {
532
- return Either.match(either, { onLeft: fail<E>, onRight: success<A> })
533
- }
534
-
535
- export function fromOption<A>(option: Option.Option<A>): AsyncData<A> {
536
- return Option.match(option, { onSome: success<A>, onNone: noData<A> })
537
- }
538
-
539
- export const map: {
540
- <A, B>(f: (a: A) => B): <E>(data: AsyncData<A, E>) => AsyncData<B, E>
541
- <A, E, B>(data: AsyncData<A, E>, f: (a: A) => B): AsyncData<B, E>
542
- } = dual(2, function map<A, E, B>(data: AsyncData<A, E>, f: (a: A) => B): AsyncData<B, E> {
543
- if (data._tag === 'Success') {
544
- return new Success(f(data.value))
545
- } else if (data._tag === 'Refreshing' && data.previous._tag === 'Success') {
546
- return new Refreshing(new Success(f(data.previous.value)), data.progress)
547
- } else if (data._tag === 'Optimistic') {
548
- if (data.previous._tag === 'Success') {
549
- return new Optimistic(new Success(f(data.previous.value)), f(data.value))
550
- } else if (data.previous._tag === 'Failure') {
551
- return new Optimistic(data.previous, f(data.value))
552
- }
553
- }
554
-
555
- return data as AsyncData<B, E>
556
- })
557
-
558
- export const flatMap: {
559
- <A, B, E2>(f: (a: A) => AsyncData<B, E2>): <E>(data: AsyncData<A, E>) => AsyncData<B, E | E2>
560
- <A, E, B, E2>(data: AsyncData<A, E>, f: (a: A) => AsyncData<B, E2>): AsyncData<B, E | E2>
561
- } = dual(2, function flatMap<
562
- A,
563
- E,
564
- B,
565
- E2,
566
- >(data: AsyncData<A, E>, f: (a: A) => AsyncData<B, E2>): AsyncData<B, E | E2> {
567
- if (data._tag === 'Success' || data._tag === 'Optimistic') {
568
- return f(data.value)
569
- } else if (data._tag === 'Refreshing' && data.previous._tag === 'Success') {
570
- return f(data.previous.value)
571
- }
572
-
573
- return data as AsyncData<B, E>
574
- })
575
-
576
- export function isNoData<A, E>(data: AsyncData<A, E>): data is NoData {
577
- return data._tag === 'NoData'
578
- }
579
-
580
- export function isLoading<A, E>(data: AsyncData<A, E>): data is Loading {
581
- return data._tag === 'Loading'
582
- }
583
-
584
- export function isSuccess<A, E>(data: AsyncData<A, E>): data is Success<A> {
585
- return data._tag === 'Success'
586
- }
587
-
588
- export function isFailure<A, E>(data: AsyncData<A, E>): data is Failure<E> {
589
- return data._tag === 'Failure'
590
- }
591
-
592
- export function isRefreshing<A, E>(data: AsyncData<A, E>): data is Refreshing<A, E> {
593
- return data._tag === 'Refreshing'
594
- }
595
-
596
- export function isLoadingOrRefreshing<A, E>(
597
- data: AsyncData<A, E>,
598
- ): data is Loading | Refreshing<A, E> {
599
- return isLoading(data) || isRefreshing(data)
600
- }
601
-
602
- export function isOptimistic<A, E>(data: AsyncData<A, E>): data is Optimistic<A, E> {
603
- return data._tag === 'Optimistic'
604
- }
605
-
606
- export function makeEquivalence<A, E>(
607
- eqA: Equivalence.Equivalence<A>,
608
- eqB: Equivalence.Equivalence<E>,
609
- ): Equivalence.Equivalence<AsyncData<A, E>> {
610
- const eqCause = Equivalence.make((a: Cause.Cause<E>, b: Cause.Cause<E>) => {
611
- const failuresA = Array.from(Cause.failures(a))
612
- const failuresB = Array.from(Cause.failures(b))
613
- if (failuresA.length > 0) {
614
- return (
615
- failuresA.length === failuresB.length && failuresA.every((e, i) => eqB(e, failuresB[i]))
616
- )
617
- }
618
-
619
- return Equal.equals(a, b)
620
- })
621
-
622
- const eq: Equivalence.Equivalence<AsyncData<A, E>> = Equivalence.make((a, b) =>
623
- matchAll(a, {
624
- NoData: () => isNoData(b),
625
- Loading: (progress) => isLoading(b) && Equal.equals(progress, b.progress),
626
- Success: (value) => isSuccess(b) && eqA(value, b.value),
627
- Failure: (cause) => isFailure(b) && eqCause(cause, b.cause),
628
- Refreshing: (previous, progress) =>
629
- isRefreshing(b) && eq(previous, b.previous) && Equal.equals(progress, b.progress),
630
- Optimistic: (value, previous) =>
631
- isOptimistic(b) && eqA(value, b.value) && eq(previous, b.previous),
632
- }),
633
- )
634
-
635
- return eq
636
- }
637
-
638
- type EqValue<T> = T extends Equivalence.Equivalence<infer A> ? A : never
639
-
640
- function unionEquivalence<EQS extends ReadonlyArray<Equivalence.Equivalence<any>>>(
641
- eqs: EQS,
642
- ): Equivalence.Equivalence<EqValue<EQS[number]>> {
643
- return (a, b) => {
644
- for (const eq of eqs) {
645
- if (eq(a, b)) {
646
- return true
647
- }
648
- }
649
-
650
- return false
651
- }
652
- }
653
-
654
- export const equals = makeEquivalence(Equal.equals, Equal.equals)