@typed/async-data 0.3.3 → 0.4.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/TypeId.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+
5
+ /**
6
+ * @since 1.0.0
7
+ */
8
+ export const AsyncDataTypeId = Symbol.for("@typed/async-data/AsyncData")
9
+
10
+ /**
11
+ * @since 1.0.0
12
+ */
13
+ export type AsyncDataTypeId = typeof AsyncDataTypeId
@@ -1,24 +1,23 @@
1
1
  // Internal
2
2
 
3
- import * as Cause from "effect/Cause"
3
+ import type * as Cause from "effect/Cause"
4
4
  import * as Effect from "effect/Effect"
5
5
  import * as Effectable from "effect/Effectable"
6
6
  import * as Equal from "effect/Equal"
7
7
  import { constant, pipe } from "effect/Function"
8
8
  import * as Hash from "effect/Hash"
9
- import * as Option from "effect/Option"
10
- import * as Unify from "effect/Unify"
11
- import { type AsyncData, type Failure, type Loading, type Success } from "../AsyncData.js"
12
- import { FAILURE_TAG, LOADING_TAG, NO_DATA_TAG, SUCCESS_TAG } from "./tag.js"
9
+ import type * as Option from "effect/Option"
10
+ import { hasProperty } from "effect/Predicate"
11
+ import type { AsyncData, Failure, Loading, Optimistic, Success } from "../AsyncData.js"
12
+ import { AsyncDataTypeId } from "../TypeId.js"
13
+ import { FAILURE_TAG, OPTIMISTIC_TAG, SUCCESS_TAG } from "./tag.js"
13
14
 
15
+ // @ts-expect-error
14
16
  export class FailureImpl<E> extends Effectable.Class<never, E, never> implements Failure<E> {
15
- readonly _tag = "Failure"
17
+ readonly [AsyncDataTypeId]: AsyncDataTypeId = AsyncDataTypeId
18
+ readonly _tag = FAILURE_TAG
16
19
 
17
- commit: () => Effect.Effect<never, E, never>;
18
-
19
- [Unify.typeSymbol]!: unknown;
20
- [Unify.unifySymbol]!: AsyncData.Unify<this>;
21
- [Unify.ignoreSymbol]!: AsyncData.IgnoreList
20
+ commit: () => Effect.Effect<never, E, never>
22
21
 
23
22
  constructor(readonly cause: Cause.Cause<E>, readonly timestamp: number, readonly refreshing: Option.Option<Loading>) {
24
23
  super()
@@ -26,30 +25,38 @@ export class FailureImpl<E> extends Effectable.Class<never, E, never> implements
26
25
  this.commit = constant(Effect.failCause(cause))
27
26
  }
28
27
 
29
- [Equal.symbol] = (that: unknown) => {
30
- return isAsyncData(that) && that._tag === "Failure"
31
- && Equal.equals(this.cause, that.cause)
32
- && Equal.equals(this.timestamp, that.timestamp)
28
+ [Equal.symbol](that: unknown) {
29
+ if (this === that) return true
30
+
31
+ if (!isAsyncData(that) || that._tag !== FAILURE_TAG) return false
32
+
33
+ console.log(
34
+ Equal.equals(this.cause, that.cause),
35
+ this.timestamp === that.timestamp,
36
+ Equal.equals(this.refreshing, that.refreshing)
37
+ )
38
+
39
+ return Equal.equals(this.cause, that.cause)
40
+ && this.timestamp === that.timestamp
33
41
  && Equal.equals(this.refreshing, that.refreshing)
34
- };
42
+ }
35
43
 
36
- [Hash.symbol] = () => {
44
+ [Hash.symbol]() {
37
45
  return pipe(
38
46
  Hash.string(this._tag),
39
47
  Hash.combine(Hash.hash(this.cause)),
48
+ Hash.combine(Hash.hash(this.timestamp)),
40
49
  Hash.combine(Hash.hash(this.refreshing))
41
50
  )
42
51
  }
43
52
  }
44
53
 
54
+ // @ts-expect-error
45
55
  export class SuccessImpl<A> extends Effectable.Class<never, never, A> implements Success<A> {
46
- readonly _tag = "Success"
56
+ readonly [AsyncDataTypeId]: AsyncDataTypeId = AsyncDataTypeId
57
+ readonly _tag = SUCCESS_TAG
47
58
 
48
- commit: () => Effect.Effect<never, never, A>;
49
-
50
- [Unify.typeSymbol]!: unknown;
51
- [Unify.unifySymbol]!: AsyncData.Unify<this>;
52
- [Unify.ignoreSymbol]!: AsyncData.IgnoreList
59
+ commit: () => Effect.Effect<never, never, A>
53
60
 
54
61
  constructor(readonly value: A, readonly timestamp: number, readonly refreshing: Option.Option<Loading>) {
55
62
  super()
@@ -57,53 +64,57 @@ export class SuccessImpl<A> extends Effectable.Class<never, never, A> implements
57
64
  this.commit = constant(Effect.succeed(value))
58
65
  }
59
66
 
60
- [Equal.symbol] = (that: unknown) => {
61
- return isAsyncData(that) && that._tag === "Success"
67
+ [Equal.symbol](that: unknown) {
68
+ return isAsyncData(that) && that._tag === SUCCESS_TAG
62
69
  && Equal.equals(this.value, that.value)
63
70
  && Equal.equals(this.timestamp, that.timestamp)
64
71
  && Equal.equals(this.refreshing, that.refreshing)
65
- };
72
+ }
66
73
 
67
- [Hash.symbol] = () => {
74
+ [Hash.symbol]() {
68
75
  return pipe(
69
76
  Hash.string(this._tag),
70
77
  Hash.combine(Hash.hash(this.value)),
78
+ Hash.combine(Hash.hash(this.timestamp)),
71
79
  Hash.combine(Hash.hash(this.refreshing))
72
80
  )
73
81
  }
74
82
  }
75
83
 
76
- export function hasDataOptions(u: Record<PropertyKey, unknown>): boolean {
77
- if ("timestamp" in u && "refreshing" in u) {
78
- return typeof u.timestamp === "bigint" && Option.isOption(u.refreshing)
79
- } else return false
80
- }
84
+ // @ts-expect-error
85
+ export class OptimisticImpl<E, A> extends Effectable.Class<never, never, A> implements Optimistic<E, A> {
86
+ readonly [AsyncDataTypeId]: AsyncDataTypeId = AsyncDataTypeId
87
+ readonly _tag = OPTIMISTIC_TAG
81
88
 
82
- export function hasEquality(u: Record<PropertyKey, unknown>): boolean {
83
- return Equal.symbol in u && Hash.symbol in u
84
- }
89
+ commit: () => Effect.Effect<never, never, A>
85
90
 
86
- export function isTaggedRecord(u: unknown): u is Record<PropertyKey, unknown> & { readonly _tag: unknown } {
87
- return isRecord(u) && "_tag" in u
88
- }
91
+ constructor(
92
+ readonly value: A,
93
+ readonly timestamp: number,
94
+ readonly previous: AsyncData<E, A>
95
+ ) {
96
+ super()
89
97
 
90
- export function isRecord(u: unknown): u is Record<PropertyKey, unknown> {
91
- return typeof u === "object" && u !== null && !Array.isArray(u)
98
+ this.commit = constant(Effect.succeed(value))
99
+ }
100
+
101
+ [Equal.symbol](that: unknown) {
102
+ return isAsyncData(that) && that._tag === OPTIMISTIC_TAG
103
+ && Equal.equals(this.value, that.value)
104
+ && Equal.equals(this.timestamp, that.timestamp)
105
+ && Equal.equals(this.previous, that.previous)
106
+ }
107
+
108
+ [Hash.symbol]() {
109
+ return pipe(
110
+ Hash.string(this._tag),
111
+ Hash.combine(Hash.hash(this.value)),
112
+ Hash.combine(Hash.hash(this.timestamp)),
113
+ Hash.combine(Hash.hash(this.previous))
114
+ )
115
+ }
92
116
  }
93
117
 
94
118
  export function isAsyncData<E, A>(u: unknown): u is AsyncData<E, A> {
95
- if (isTaggedRecord(u) && hasEquality(u)) {
96
- switch (u._tag) {
97
- case NO_DATA_TAG:
98
- return "timstamp" in u && typeof u.timestamp === "bigint"
99
- case LOADING_TAG:
100
- return "progress" in u && Option.isOption(u.progress)
101
- case FAILURE_TAG:
102
- return hasDataOptions(u) && "cause" in u && Cause.isCause(u.cause)
103
- case SUCCESS_TAG:
104
- return hasDataOptions(u) && "value" in u
105
- default:
106
- return false
107
- }
108
- } else return false
119
+ return hasProperty(u, AsyncDataTypeId)
109
120
  }
@@ -5,3 +5,5 @@ export const LOADING_TAG = "Loading" as const
5
5
  export const FAILURE_TAG = "Failure" as const
6
6
 
7
7
  export const SUCCESS_TAG = "Success" as const
8
+
9
+ export const OPTIMISTIC_TAG = "Optimistic" as const