@zeix/cause-effect 0.17.3 → 0.18.1
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/.ai-context.md +169 -227
- package/.cursorrules +41 -35
- package/.github/copilot-instructions.md +176 -116
- package/ARCHITECTURE.md +276 -0
- package/CHANGELOG.md +29 -0
- package/CLAUDE.md +201 -143
- package/GUIDE.md +298 -0
- package/README.md +246 -193
- package/REQUIREMENTS.md +100 -0
- package/bench/reactivity.bench.ts +577 -0
- package/context7.json +4 -0
- package/examples/events-sensor.ts +187 -0
- package/examples/selector-sensor.ts +173 -0
- package/index.dev.js +1390 -1008
- package/index.js +1 -1
- package/index.ts +60 -74
- package/package.json +5 -2
- package/skills/changelog-keeper/SKILL.md +59 -0
- package/skills/changelog-keeper/agents/openai.yaml +4 -0
- package/src/errors.ts +118 -74
- package/src/graph.ts +612 -0
- package/src/nodes/collection.ts +512 -0
- package/src/nodes/effect.ts +149 -0
- package/src/nodes/list.ts +589 -0
- package/src/nodes/memo.ts +148 -0
- package/src/nodes/sensor.ts +149 -0
- package/src/nodes/state.ts +135 -0
- package/src/nodes/store.ts +378 -0
- package/src/nodes/task.ts +174 -0
- package/src/signal.ts +112 -66
- package/src/util.ts +26 -57
- package/test/batch.test.ts +96 -62
- package/test/benchmark.test.ts +473 -487
- package/test/collection.test.ts +456 -707
- package/test/effect.test.ts +293 -696
- package/test/list.test.ts +335 -592
- package/test/memo.test.ts +574 -0
- package/test/regression.test.ts +156 -0
- package/test/scope.test.ts +191 -0
- package/test/sensor.test.ts +454 -0
- package/test/signal.test.ts +220 -213
- package/test/state.test.ts +217 -265
- package/test/store.test.ts +346 -446
- package/test/task.test.ts +529 -0
- package/test/untrack.test.ts +167 -0
- package/types/index.d.ts +13 -15
- package/types/src/errors.d.ts +73 -17
- package/types/src/graph.d.ts +218 -0
- package/types/src/nodes/collection.d.ts +69 -0
- package/types/src/nodes/effect.d.ts +48 -0
- package/types/src/nodes/list.d.ts +66 -0
- package/types/src/nodes/memo.d.ts +63 -0
- package/types/src/nodes/sensor.d.ts +81 -0
- package/types/src/nodes/state.d.ts +78 -0
- package/types/src/nodes/store.d.ts +51 -0
- package/types/src/nodes/task.d.ts +79 -0
- package/types/src/signal.d.ts +43 -29
- package/types/src/util.d.ts +9 -16
- package/archive/benchmark.ts +0 -683
- package/archive/collection.ts +0 -253
- package/archive/composite.ts +0 -85
- package/archive/computed.ts +0 -195
- package/archive/list.ts +0 -483
- package/archive/memo.ts +0 -139
- package/archive/state.ts +0 -90
- package/archive/store.ts +0 -298
- package/archive/task.ts +0 -189
- package/src/classes/collection.ts +0 -245
- package/src/classes/computed.ts +0 -349
- package/src/classes/list.ts +0 -343
- package/src/classes/ref.ts +0 -70
- package/src/classes/state.ts +0 -102
- package/src/classes/store.ts +0 -262
- package/src/diff.ts +0 -138
- package/src/effect.ts +0 -93
- package/src/match.ts +0 -45
- package/src/resolve.ts +0 -49
- package/src/system.ts +0 -257
- package/test/computed.test.ts +0 -1108
- package/test/diff.test.ts +0 -955
- package/test/match.test.ts +0 -388
- package/test/ref.test.ts +0 -353
- package/test/resolve.test.ts +0 -154
- package/types/src/classes/collection.d.ts +0 -45
- package/types/src/classes/computed.d.ts +0 -94
- package/types/src/classes/list.d.ts +0 -43
- package/types/src/classes/ref.d.ts +0 -35
- package/types/src/classes/state.d.ts +0 -49
- package/types/src/classes/store.d.ts +0 -52
- package/types/src/diff.d.ts +0 -28
- package/types/src/effect.d.ts +0 -15
- package/types/src/match.d.ts +0 -21
- package/types/src/resolve.d.ts +0 -29
- package/types/src/system.d.ts +0 -78
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateCallback,
|
|
3
|
+
validateReadValue,
|
|
4
|
+
validateSignalValue,
|
|
5
|
+
} from '../errors'
|
|
6
|
+
import {
|
|
7
|
+
activeSink,
|
|
8
|
+
batchDepth,
|
|
9
|
+
type ComputedOptions,
|
|
10
|
+
DEFAULT_EQUALITY,
|
|
11
|
+
FLAG_DIRTY,
|
|
12
|
+
flush,
|
|
13
|
+
link,
|
|
14
|
+
type MemoCallback,
|
|
15
|
+
type MemoNode,
|
|
16
|
+
propagate,
|
|
17
|
+
refresh,
|
|
18
|
+
type SinkNode,
|
|
19
|
+
TYPE_MEMO,
|
|
20
|
+
} from '../graph'
|
|
21
|
+
import { isObjectOfType, isSyncFunction } from '../util'
|
|
22
|
+
|
|
23
|
+
/* === Types === */
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A derived reactive computation that caches its result.
|
|
27
|
+
* Automatically tracks dependencies and recomputes when they change.
|
|
28
|
+
*
|
|
29
|
+
* @template T - The type of value computed by the memo
|
|
30
|
+
*/
|
|
31
|
+
type Memo<T extends {}> = {
|
|
32
|
+
readonly [Symbol.toStringTag]: 'Memo'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Gets the current value of the memo.
|
|
36
|
+
* Recomputes if dependencies have changed since last access.
|
|
37
|
+
* When called inside another reactive context, creates a dependency.
|
|
38
|
+
* @returns The computed value
|
|
39
|
+
* @throws UnsetSignalValueError If the memo value is still unset when read.
|
|
40
|
+
*/
|
|
41
|
+
get(): T
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* === Exported Functions === */
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates a derived reactive computation that caches its result.
|
|
48
|
+
* The computation automatically tracks dependencies and recomputes when they change.
|
|
49
|
+
* Uses lazy evaluation - only computes when the value is accessed.
|
|
50
|
+
*
|
|
51
|
+
* @since 0.18.0
|
|
52
|
+
* @template T - The type of value computed by the memo
|
|
53
|
+
* @param fn - The computation function that receives the previous value
|
|
54
|
+
* @param options - Optional configuration for the memo
|
|
55
|
+
* @param options.value - Optional initial value for reducer patterns
|
|
56
|
+
* @param options.equals - Optional equality function. Defaults to strict equality (`===`)
|
|
57
|
+
* @param options.guard - Optional type guard to validate values
|
|
58
|
+
* @param options.watched - Optional callback invoked when the memo is first watched by an effect.
|
|
59
|
+
* Receives an `invalidate` function to mark the memo dirty and trigger recomputation.
|
|
60
|
+
* Must return a cleanup function called when no effects are watching.
|
|
61
|
+
* @returns A Memo object with a get() method
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const count = createState(0);
|
|
66
|
+
* const doubled = createMemo(() => count.get() * 2);
|
|
67
|
+
* console.log(doubled.get()); // 0
|
|
68
|
+
* count.set(5);
|
|
69
|
+
* console.log(doubled.get()); // 10
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* // Using previous value
|
|
75
|
+
* const sum = createMemo((prev) => prev + count.get(), { value: 0, equals: Object.is });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
function createMemo<T extends {}>(
|
|
79
|
+
fn: (prev: T) => T,
|
|
80
|
+
options: ComputedOptions<T> & { value: T },
|
|
81
|
+
): Memo<T>
|
|
82
|
+
function createMemo<T extends {}>(
|
|
83
|
+
fn: MemoCallback<T>,
|
|
84
|
+
options?: ComputedOptions<T>,
|
|
85
|
+
): Memo<T>
|
|
86
|
+
function createMemo<T extends {}>(
|
|
87
|
+
fn: MemoCallback<T>,
|
|
88
|
+
options?: ComputedOptions<T>,
|
|
89
|
+
): Memo<T> {
|
|
90
|
+
validateCallback(TYPE_MEMO, fn, isSyncFunction)
|
|
91
|
+
if (options?.value !== undefined)
|
|
92
|
+
validateSignalValue(TYPE_MEMO, options.value, options?.guard)
|
|
93
|
+
|
|
94
|
+
const node: MemoNode<T> = {
|
|
95
|
+
fn,
|
|
96
|
+
value: options?.value as T,
|
|
97
|
+
flags: FLAG_DIRTY,
|
|
98
|
+
sources: null,
|
|
99
|
+
sourcesTail: null,
|
|
100
|
+
sinks: null,
|
|
101
|
+
sinksTail: null,
|
|
102
|
+
equals: options?.equals ?? DEFAULT_EQUALITY,
|
|
103
|
+
error: undefined,
|
|
104
|
+
stop: undefined,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const watched = options?.watched
|
|
108
|
+
const subscribe = watched
|
|
109
|
+
? () => {
|
|
110
|
+
if (activeSink) {
|
|
111
|
+
if (!node.sinks)
|
|
112
|
+
node.stop = watched(() => {
|
|
113
|
+
node.flags |= FLAG_DIRTY
|
|
114
|
+
for (let e = node.sinks; e; e = e.nextSink)
|
|
115
|
+
propagate(e.sink)
|
|
116
|
+
if (batchDepth === 0) flush()
|
|
117
|
+
})
|
|
118
|
+
link(node, activeSink)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
: () => {
|
|
122
|
+
if (activeSink) link(node, activeSink)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
[Symbol.toStringTag]: TYPE_MEMO,
|
|
127
|
+
get() {
|
|
128
|
+
subscribe()
|
|
129
|
+
refresh(node as unknown as SinkNode)
|
|
130
|
+
if (node.error) throw node.error
|
|
131
|
+
validateReadValue(TYPE_MEMO, node.value)
|
|
132
|
+
return node.value
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Checks if a value is a Memo signal.
|
|
139
|
+
*
|
|
140
|
+
* @since 0.18.0
|
|
141
|
+
* @param value - The value to check
|
|
142
|
+
* @returns True if the value is a Memo
|
|
143
|
+
*/
|
|
144
|
+
function isMemo<T extends {} = unknown & {}>(value: unknown): value is Memo<T> {
|
|
145
|
+
return isObjectOfType(value, TYPE_MEMO)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { createMemo, isMemo, type Memo }
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateCallback,
|
|
3
|
+
validateReadValue,
|
|
4
|
+
validateSignalValue,
|
|
5
|
+
} from '../errors'
|
|
6
|
+
import {
|
|
7
|
+
activeSink,
|
|
8
|
+
type Cleanup,
|
|
9
|
+
DEFAULT_EQUALITY,
|
|
10
|
+
link,
|
|
11
|
+
type SignalOptions,
|
|
12
|
+
type StateNode,
|
|
13
|
+
setState,
|
|
14
|
+
TYPE_SENSOR,
|
|
15
|
+
} from '../graph'
|
|
16
|
+
import { isObjectOfType, isSyncFunction } from '../util'
|
|
17
|
+
|
|
18
|
+
/* === Types === */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A read-only signal that tracks external input and updates a state value as long as it is active.
|
|
22
|
+
*
|
|
23
|
+
* @template T - The type of value produced by the sensor
|
|
24
|
+
*/
|
|
25
|
+
type Sensor<T extends {}> = {
|
|
26
|
+
readonly [Symbol.toStringTag]: 'Sensor'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Gets the current value of the sensor.
|
|
30
|
+
* When called inside another reactive context, creates a dependency.
|
|
31
|
+
* @returns The sensor value
|
|
32
|
+
* @throws UnsetSignalValueError If the sensor value is still unset when read.
|
|
33
|
+
*/
|
|
34
|
+
get(): T
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A callback function for sensors when the sensor starts being watched.
|
|
39
|
+
*
|
|
40
|
+
* @template T - The type of value observed
|
|
41
|
+
* @param set - A function to set the observed value
|
|
42
|
+
* @returns A cleanup function when the sensor stops being watched
|
|
43
|
+
*/
|
|
44
|
+
type SensorOptions<T extends {}> = SignalOptions<T> & {
|
|
45
|
+
/**
|
|
46
|
+
* Optional initial value. Avoids `UnsetSignalValueError` on first read
|
|
47
|
+
* before the watched callback fires.
|
|
48
|
+
*/
|
|
49
|
+
value?: T
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type SensorCallback<T extends {}> = (set: (next: T) => void) => Cleanup
|
|
53
|
+
|
|
54
|
+
/* === Exported Functions === */
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Creates a sensor that tracks external input and updates a state value as long as it is active.
|
|
58
|
+
* Sensors get activated when they are first accessed by an effect and deactivated when they are
|
|
59
|
+
* no longer watched. This lazy activation pattern ensures resources are only consumed when needed.
|
|
60
|
+
*
|
|
61
|
+
* @since 0.18.0
|
|
62
|
+
* @template T - The type of value produced by the sensor
|
|
63
|
+
* @param watched - The callback invoked when the sensor starts being watched, receives a `set` function and returns a cleanup function.
|
|
64
|
+
* @param options - Optional configuration for the sensor.
|
|
65
|
+
* @param options.value - Optional initial value. Avoids `UnsetSignalValueError` on first read
|
|
66
|
+
* before the watched callback fires. Essential for the mutable-object observation pattern.
|
|
67
|
+
* @param options.equals - Optional equality function. Defaults to strict equality (`===`). Use `SKIP_EQUALITY`
|
|
68
|
+
* for mutable objects where the reference stays the same but internal state changes.
|
|
69
|
+
* @param options.guard - Optional type guard to validate values.
|
|
70
|
+
* @returns A read-only sensor signal.
|
|
71
|
+
*
|
|
72
|
+
* @example Tracking external values
|
|
73
|
+
* ```ts
|
|
74
|
+
* const mousePos = createSensor<{ x: number; y: number }>((set) => {
|
|
75
|
+
* const handler = (e: MouseEvent) => {
|
|
76
|
+
* set({ x: e.clientX, y: e.clientY });
|
|
77
|
+
* };
|
|
78
|
+
* window.addEventListener('mousemove', handler);
|
|
79
|
+
* return () => window.removeEventListener('mousemove', handler);
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @example Observing a mutable object
|
|
84
|
+
* ```ts
|
|
85
|
+
* import { createSensor, SKIP_EQUALITY } from 'cause-effect';
|
|
86
|
+
*
|
|
87
|
+
* const el = createSensor<HTMLElement>((set) => {
|
|
88
|
+
* const node = document.getElementById('box')!;
|
|
89
|
+
* set(node);
|
|
90
|
+
* const obs = new MutationObserver(() => set(node));
|
|
91
|
+
* obs.observe(node, { attributes: true });
|
|
92
|
+
* return () => obs.disconnect();
|
|
93
|
+
* }, { value: node, equals: SKIP_EQUALITY });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
function createSensor<T extends {}>(
|
|
97
|
+
watched: SensorCallback<T>,
|
|
98
|
+
options?: SensorOptions<T>,
|
|
99
|
+
): Sensor<T> {
|
|
100
|
+
validateCallback(TYPE_SENSOR, watched, isSyncFunction)
|
|
101
|
+
if (options?.value !== undefined)
|
|
102
|
+
validateSignalValue(TYPE_SENSOR, options.value, options?.guard)
|
|
103
|
+
|
|
104
|
+
const node: StateNode<T> = {
|
|
105
|
+
value: options?.value as T,
|
|
106
|
+
sinks: null,
|
|
107
|
+
sinksTail: null,
|
|
108
|
+
equals: options?.equals ?? DEFAULT_EQUALITY,
|
|
109
|
+
guard: options?.guard,
|
|
110
|
+
stop: undefined,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
[Symbol.toStringTag]: TYPE_SENSOR,
|
|
115
|
+
get(): T {
|
|
116
|
+
if (activeSink) {
|
|
117
|
+
if (!node.sinks)
|
|
118
|
+
node.stop = watched((next: T): void => {
|
|
119
|
+
validateSignalValue(TYPE_SENSOR, next, node.guard)
|
|
120
|
+
setState(node, next)
|
|
121
|
+
})
|
|
122
|
+
link(node, activeSink)
|
|
123
|
+
}
|
|
124
|
+
validateReadValue(TYPE_SENSOR, node.value)
|
|
125
|
+
return node.value
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Checks if a value is a Sensor signal.
|
|
132
|
+
*
|
|
133
|
+
* @since 0.18.0
|
|
134
|
+
* @param value - The value to check
|
|
135
|
+
* @returns True if the value is a Sensor
|
|
136
|
+
*/
|
|
137
|
+
function isSensor<T extends {} = unknown & {}>(
|
|
138
|
+
value: unknown,
|
|
139
|
+
): value is Sensor<T> {
|
|
140
|
+
return isObjectOfType(value, TYPE_SENSOR)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export {
|
|
144
|
+
createSensor,
|
|
145
|
+
isSensor,
|
|
146
|
+
type Sensor,
|
|
147
|
+
type SensorCallback,
|
|
148
|
+
type SensorOptions,
|
|
149
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { validateCallback, validateSignalValue } from '../errors'
|
|
2
|
+
import {
|
|
3
|
+
activeSink,
|
|
4
|
+
DEFAULT_EQUALITY,
|
|
5
|
+
link,
|
|
6
|
+
type SignalOptions,
|
|
7
|
+
type StateNode,
|
|
8
|
+
setState,
|
|
9
|
+
TYPE_STATE,
|
|
10
|
+
} from '../graph'
|
|
11
|
+
import { isObjectOfType } from '../util'
|
|
12
|
+
|
|
13
|
+
/* === Types === */
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A callback function for states that updates a value based on the previous value.
|
|
17
|
+
*
|
|
18
|
+
* @template T - The type of value
|
|
19
|
+
* @param prev - The previous state value
|
|
20
|
+
* @returns The new state value
|
|
21
|
+
*/
|
|
22
|
+
type UpdateCallback<T extends {}> = (prev: T) => T
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A mutable reactive state container.
|
|
26
|
+
* Changes to the state will automatically propagate to dependent computations and effects.
|
|
27
|
+
*
|
|
28
|
+
* @template T - The type of value stored in the state
|
|
29
|
+
*/
|
|
30
|
+
type State<T extends {}> = {
|
|
31
|
+
readonly [Symbol.toStringTag]: 'State'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets the current value of the state.
|
|
35
|
+
* When called inside a memo, task, or effect, creates a dependency.
|
|
36
|
+
* @returns The current value
|
|
37
|
+
*/
|
|
38
|
+
get(): T
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Sets a new value for the state.
|
|
42
|
+
* If the new value is different (according to the equality function), all dependents will be notified.
|
|
43
|
+
* @param next - The new value to set
|
|
44
|
+
*/
|
|
45
|
+
set(next: T): void
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Updates the state with a new value computed by a callback function.
|
|
49
|
+
* The callback receives the current value as an argument.
|
|
50
|
+
* @param fn - The callback function to compute the new value
|
|
51
|
+
*/
|
|
52
|
+
update(fn: UpdateCallback<T>): void
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* === Exported Functions === */
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a mutable reactive state container.
|
|
59
|
+
*
|
|
60
|
+
* @since 0.9.0
|
|
61
|
+
* @template T - The type of value stored in the state
|
|
62
|
+
* @param value - The initial value
|
|
63
|
+
* @param options - Optional configuration for the state
|
|
64
|
+
* @returns A State object with get() and set() methods
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const count = createState(0);
|
|
69
|
+
* count.set(1);
|
|
70
|
+
* console.log(count.get()); // 1
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* // With type guard
|
|
76
|
+
* const count = createState(0, {
|
|
77
|
+
* guard: (v): v is number => typeof v === 'number'
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
function createState<T extends {}>(
|
|
82
|
+
value: T,
|
|
83
|
+
options?: SignalOptions<T>,
|
|
84
|
+
): State<T> {
|
|
85
|
+
validateSignalValue(TYPE_STATE, value, options?.guard)
|
|
86
|
+
|
|
87
|
+
const node: StateNode<T> = {
|
|
88
|
+
value,
|
|
89
|
+
sinks: null,
|
|
90
|
+
sinksTail: null,
|
|
91
|
+
equals: options?.equals ?? DEFAULT_EQUALITY,
|
|
92
|
+
guard: options?.guard,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
[Symbol.toStringTag]: TYPE_STATE,
|
|
97
|
+
get(): T {
|
|
98
|
+
if (activeSink) link(node, activeSink)
|
|
99
|
+
return node.value
|
|
100
|
+
},
|
|
101
|
+
set(next: T): void {
|
|
102
|
+
validateSignalValue(TYPE_STATE, next, node.guard)
|
|
103
|
+
setState(node, next)
|
|
104
|
+
},
|
|
105
|
+
update(fn: UpdateCallback<T>): void {
|
|
106
|
+
validateCallback(TYPE_STATE, fn)
|
|
107
|
+
const next = fn(node.value)
|
|
108
|
+
validateSignalValue(TYPE_STATE, next, node.guard)
|
|
109
|
+
setState(node, next)
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Checks if a value is a State signal.
|
|
116
|
+
*
|
|
117
|
+
* @since 0.9.0
|
|
118
|
+
* @param value - The value to check
|
|
119
|
+
* @returns True if the value is a State
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* const state = createState(0);
|
|
124
|
+
* if (isState(state)) {
|
|
125
|
+
* state.set(1); // TypeScript knows state has set()
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
function isState<T extends {} = unknown & {}>(
|
|
130
|
+
value: unknown,
|
|
131
|
+
): value is State<T> {
|
|
132
|
+
return isObjectOfType(value, TYPE_STATE)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { createState, isState, type State, type UpdateCallback }
|