Skip to content

Commit 8764061

Browse files
committed
improve Serializable compatibility
1 parent d06af3e commit 8764061

File tree

7 files changed

+79
-30
lines changed

7 files changed

+79
-30
lines changed

.changeset/thick-apes-make.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@effect-atom/atom-react": patch
3+
"@effect-atom/atom": patch
4+
---
5+
6+
improve Serializable compatibility

docs/atom/Atom.ts.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,11 @@ Added in v1.0.0
323323
**Signature**
324324
325325
```ts
326-
export interface Serializable {
326+
export interface Serializable<S extends Schema.Schema.Any> {
327327
readonly [SerializableTypeId]: {
328328
readonly key: string
329-
readonly encode: (value: unknown) => unknown
330-
readonly decode: (value: unknown) => unknown
329+
readonly encode: (value: S["Type"]) => S["Encoded"]
330+
readonly decode: (value: S["Encoded"]) => S["Type"]
331331
}
332332
}
333333
```
@@ -359,7 +359,7 @@ Added in v1.0.0
359359
**Signature**
360360
361361
```ts
362-
export declare const isSerializable: (self: Atom<any>) => self is Atom<any> & Serializable
362+
export declare const isSerializable: (self: Atom<any>) => self is Atom<any> & Serializable<any>
363363
```
364364
365365
Added in v1.0.0
@@ -548,14 +548,14 @@ Added in v1.0.0
548548
549549
```ts
550550
export declare const serializable: {
551-
<R extends Atom<any>, I>(options: {
551+
<R extends Atom<any>, S extends Schema.Schema<Type<R>, any>>(options: {
552552
readonly key: string
553-
readonly schema: Schema.Schema<Type<R>, I>
554-
}): (self: R) => R & Serializable
555-
<R extends Atom<any>, I>(
553+
readonly schema: S
554+
}): (self: R) => R & Serializable<S>
555+
<R extends Atom<any>, S extends Schema.Schema<Type<R>, any>>(
556556
self: R,
557-
options: { readonly key: string; readonly schema: Schema.Schema<Type<R>, I> }
558-
): R & Serializable
557+
options: { readonly key: string; readonly schema: S }
558+
): R & Serializable<S>
559559
}
560560
```
561561

docs/atom/Hydration.ts.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ Added in v1.0.0
1414

1515
- [dehydration](#dehydration)
1616
- [dehydrate](#dehydrate)
17+
- [toValues](#tovalues)
1718
- [hydration](#hydration)
1819
- [hydrate](#hydrate)
1920
- [models](#models)
2021
- [DehydratedAtom (interface)](#dehydratedatom-interface)
22+
- [DehydratedAtomValue (interface)](#dehydratedatomvalue-interface)
2123

2224
---
2325

@@ -36,6 +38,16 @@ export declare const dehydrate: (
3638
3739
Added in v1.0.0
3840
41+
## toValues
42+
43+
**Signature**
44+
45+
```ts
46+
export declare const toValues: (state: ReadonlyArray<DehydratedAtom>) => Array<DehydratedAtomValue>
47+
```
48+
49+
Added in v1.0.0
50+
3951
# hydration
4052
4153
## hydrate
@@ -56,6 +68,18 @@ Added in v1.0.0
5668
5769
```ts
5870
export interface DehydratedAtom {
71+
readonly "~@effect-atom/atom/DehydratedAtom": true
72+
}
73+
```
74+
75+
Added in v1.0.0
76+
77+
## DehydratedAtomValue (interface)
78+
79+
**Signature**
80+
81+
```ts
82+
export interface DehydratedAtomValue extends DehydratedAtom {
5983
readonly key: string
6084
readonly value: unknown
6185
readonly dehydratedAt: number

packages/atom-react/src/ReactHydration.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ export const HydrationBoundary: React.FC<HydrationBoundaryProps> = ({
4040
// If the transition is aborted, we will have hydrated any _new_ Atom values, but
4141
// we throw away the fresh data for any existing ones to avoid unexpectedly
4242
// updating the UI.
43-
const hydrationQueue: Array<Hydration.DehydratedAtom> | undefined = React.useMemo(() => {
43+
const hydrationQueue: Array<Hydration.DehydratedAtomValue> | undefined = React.useMemo(() => {
4444
if (state) {
45-
const dehydratedAtoms = Array.from(state)
45+
const dehydratedAtoms = Array.from(state) as Array<Hydration.DehydratedAtomValue>
4646
const nodes = registry.getNodes()
4747

48-
const newDehydratedAtoms: Array<Hydration.DehydratedAtom> = []
49-
const existingDehydratedAtoms: Array<Hydration.DehydratedAtom> = []
48+
const newDehydratedAtoms: Array<Hydration.DehydratedAtomValue> = []
49+
const existingDehydratedAtoms: Array<Hydration.DehydratedAtomValue> = []
5050

5151
for (const dehydratedAtom of dehydratedAtoms) {
5252
const existingNode = nodes.get(dehydratedAtom.key)

packages/atom/src/Atom.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,37 +2023,37 @@ export type SerializableTypeId = "~effect-atom/atom/Atom/Serializable"
20232023
* @since 1.0.0
20242024
* @category Serializable
20252025
*/
2026-
export interface Serializable {
2026+
export interface Serializable<S extends Schema.Schema.Any> {
20272027
readonly [SerializableTypeId]: {
20282028
readonly key: string
2029-
readonly encode: (value: unknown) => unknown
2030-
readonly decode: (value: unknown) => unknown
2029+
readonly encode: (value: S["Type"]) => S["Encoded"]
2030+
readonly decode: (value: S["Encoded"]) => S["Type"]
20312031
}
20322032
}
20332033

20342034
/**
20352035
* @since 1.0.0
20362036
* @category Serializable
20372037
*/
2038-
export const isSerializable = (self: Atom<any>): self is Atom<any> & Serializable => SerializableTypeId in self
2038+
export const isSerializable = (self: Atom<any>): self is Atom<any> & Serializable<any> => SerializableTypeId in self
20392039

20402040
/**
20412041
* @since 1.0.0
20422042
* @category combinators
20432043
*/
20442044
export const serializable: {
2045-
<R extends Atom<any>, I>(options: {
2045+
<R extends Atom<any>, S extends Schema.Schema<Type<R>, any>>(options: {
20462046
readonly key: string
2047-
readonly schema: Schema.Schema<Type<R>, I>
2048-
}): (self: R) => R & Serializable
2049-
<R extends Atom<any>, I>(self: R, options: {
2047+
readonly schema: S
2048+
}): (self: R) => R & Serializable<S>
2049+
<R extends Atom<any>, S extends Schema.Schema<Type<R>, any>>(self: R, options: {
20502050
readonly key: string
2051-
readonly schema: Schema.Schema<Type<R>, I>
2052-
}): R & Serializable
2051+
readonly schema: S
2052+
}): R & Serializable<S>
20532053
} = dual(2, <R extends Atom<any>, A, I>(self: R, options: {
20542054
readonly key: string
20552055
readonly schema: Schema.Schema<A, I>
2056-
}): R & Serializable =>
2056+
}): R & Serializable<any> =>
20572057
Object.assign(Object.create(Object.getPrototypeOf(self)), {
20582058
...self,
20592059
label: self.label ?? [options.key, new Error().stack?.split("\n")[5] ?? ""],

packages/atom/src/Hydration.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ import * as Result from "./Result.js"
1111
* @category models
1212
*/
1313
export interface DehydratedAtom {
14+
readonly "~@effect-atom/atom/DehydratedAtom": true
15+
}
16+
17+
/**
18+
* @since 1.0.0
19+
* @category models
20+
*/
21+
export interface DehydratedAtomValue extends DehydratedAtom {
1422
readonly key: string
1523
readonly value: unknown
1624
readonly dehydratedAt: number
@@ -31,7 +39,7 @@ export const dehydrate = (
3139
}
3240
): Array<DehydratedAtom> => {
3341
const encodeInitialResultMode = options?.encodeInitialAs ?? "ignore"
34-
const arr = Arr.empty<DehydratedAtom>()
42+
const arr = Arr.empty<DehydratedAtomValue>()
3543
const now = Date.now()
3644
registry.getNodes().forEach((node, key) => {
3745
if (!Atom.isSerializable(node.atom)) return
@@ -55,15 +63,22 @@ export const dehydrate = (
5563
}
5664

5765
arr.push({
66+
"~@effect-atom/atom/DehydratedAtom": true,
5867
key: key as string,
5968
value: encodedValue,
6069
dehydratedAt: now,
6170
resultPromise
6271
})
6372
})
64-
return arr
73+
return arr as any
6574
}
6675

76+
/**
77+
* @since 1.0.0
78+
* @category dehydration
79+
*/
80+
export const toValues = (state: ReadonlyArray<DehydratedAtom>): Array<DehydratedAtomValue> => state as any
81+
6782
/**
6883
* @since 1.0.0
6984
* @category hydration
@@ -72,7 +87,7 @@ export const hydrate = (
7287
registry: Registry.Registry,
7388
dehydratedState: Iterable<DehydratedAtom>
7489
): void => {
75-
for (const datom of dehydratedState) {
90+
for (const datom of (dehydratedState as Iterable<DehydratedAtomValue>)) {
7691
registry.setSerializable(datom.key, datom.value)
7792

7893
// If there's a resultPromise, it means this was in Initial state when dehydrated

packages/atom/test/Atom.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,14 +1135,15 @@ describe("Atom", () => {
11351135
}))
11361136
r.mount(pending)
11371137

1138-
const state = Hydration.dehydrate(r, {
1138+
const state = Hydration.toValues(Hydration.dehydrate(r, {
11391139
encodeInitialAs: "promise"
1140-
})
1140+
}))
11411141
expect(state.map((r) => Struct.omit(r, "dehydratedAt", "resultPromise"))).toMatchInlineSnapshot(`
11421142
[
11431143
{
11441144
"key": "basicSerializable",
11451145
"value": 0,
1146+
"~@effect-atom/atom/DehydratedAtom": true,
11461147
},
11471148
{
11481149
"key": "errored",
@@ -1157,6 +1158,7 @@ describe("Atom", () => {
11571158
},
11581159
"waiting": false,
11591160
},
1161+
"~@effect-atom/atom/DehydratedAtom": true,
11601162
},
11611163
{
11621164
"key": "success",
@@ -1166,13 +1168,15 @@ describe("Atom", () => {
11661168
"value": 123,
11671169
"waiting": false,
11681170
},
1171+
"~@effect-atom/atom/DehydratedAtom": true,
11691172
},
11701173
{
11711174
"key": "pending",
11721175
"value": {
11731176
"_tag": "Initial",
11741177
"waiting": true,
11751178
},
1179+
"~@effect-atom/atom/DehydratedAtom": true,
11761180
},
11771181
]
11781182
`)

0 commit comments

Comments
 (0)