@zeix/cause-effect 0.15.1 → 0.16.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.
Files changed (48) hide show
  1. package/.ai-context.md +254 -0
  2. package/.cursorrules +54 -0
  3. package/.github/copilot-instructions.md +132 -0
  4. package/CLAUDE.md +319 -0
  5. package/README.md +167 -159
  6. package/eslint.config.js +1 -1
  7. package/index.dev.js +528 -407
  8. package/index.js +1 -1
  9. package/index.ts +36 -25
  10. package/package.json +1 -1
  11. package/src/computed.ts +41 -30
  12. package/src/diff.ts +57 -44
  13. package/src/effect.ts +15 -16
  14. package/src/errors.ts +64 -0
  15. package/src/match.ts +2 -2
  16. package/src/resolve.ts +2 -2
  17. package/src/signal.ts +27 -49
  18. package/src/state.ts +27 -19
  19. package/src/store.ts +410 -209
  20. package/src/system.ts +122 -0
  21. package/src/util.ts +45 -6
  22. package/test/batch.test.ts +18 -11
  23. package/test/benchmark.test.ts +4 -4
  24. package/test/computed.test.ts +508 -72
  25. package/test/diff.test.ts +321 -4
  26. package/test/effect.test.ts +61 -61
  27. package/test/match.test.ts +38 -28
  28. package/test/resolve.test.ts +16 -16
  29. package/test/signal.test.ts +19 -147
  30. package/test/state.test.ts +212 -25
  31. package/test/store.test.ts +1370 -134
  32. package/test/util/dependency-graph.ts +1 -1
  33. package/types/index.d.ts +10 -9
  34. package/types/src/collection.d.ts +26 -0
  35. package/types/src/computed.d.ts +9 -9
  36. package/types/src/diff.d.ts +5 -3
  37. package/types/src/effect.d.ts +3 -3
  38. package/types/src/errors.d.ts +22 -0
  39. package/types/src/match.d.ts +1 -1
  40. package/types/src/resolve.d.ts +1 -1
  41. package/types/src/signal.d.ts +12 -19
  42. package/types/src/state.d.ts +5 -5
  43. package/types/src/store.d.ts +40 -36
  44. package/types/src/system.d.ts +44 -0
  45. package/types/src/util.d.ts +7 -5
  46. package/index.d.ts +0 -36
  47. package/src/scheduler.ts +0 -172
  48. package/types/test-new-effect.d.ts +0 -1
@@ -1,16 +1,15 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import {
3
3
  type Computed,
4
- computed,
4
+ createComputed,
5
+ createState,
6
+ createStore,
5
7
  isComputed,
6
8
  isState,
7
9
  isStore,
8
10
  type Signal,
9
11
  type State,
10
12
  type Store,
11
- state,
12
- store,
13
- toMutableSignal,
14
13
  toSignal,
15
14
  type UnknownRecord,
16
15
  } from '..'
@@ -20,31 +19,28 @@ import {
20
19
  describe('toSignal', () => {
21
20
  describe('type inference and runtime behavior', () => {
22
21
  test('converts array to Store<Record<string, T>>', () => {
23
- const arr = [
22
+ const result = toSignal([
24
23
  { id: 1, name: 'Alice' },
25
24
  { id: 2, name: 'Bob' },
26
- ]
27
- const result = toSignal(arr)
25
+ ])
28
26
 
29
27
  // Runtime behavior
30
28
  expect(isStore(result)).toBe(true)
31
29
  expect(result['0'].get()).toEqual({ id: 1, name: 'Alice' })
32
30
  expect(result['1'].get()).toEqual({ id: 2, name: 'Bob' })
33
31
 
34
- // Type inference test - now correctly returns Store<Record<string, {id: number, name: string}>>
35
- const typedResult: Store<
36
- Record<string, { id: number; name: string }>
37
- > = result
32
+ // Type inference test - now correctly returns Store<Record<number, {id: number, name: string}>>
33
+ const typedResult: Store<{ id: number; name: string }[]> = result
38
34
  expect(typedResult).toBeDefined()
39
35
  })
40
36
 
41
37
  test('converts empty array to Store<Record<string, never>>', () => {
42
- const arr: never[] = []
43
- const result = toSignal(arr)
38
+ const result = toSignal([])
44
39
 
45
40
  // Runtime behavior
46
41
  expect(isStore(result)).toBe(true)
47
- expect(Object.keys(result).length).toBe(0)
42
+ expect(result.length).toBe(0)
43
+ expect(Object.keys(result).length).toBe(1) // length property
48
44
  })
49
45
 
50
46
  test('converts record to Store<T>', () => {
@@ -62,7 +58,7 @@ describe('toSignal', () => {
62
58
  })
63
59
 
64
60
  test('passes through existing Store unchanged', () => {
65
- const originalStore = store({ count: 5 })
61
+ const originalStore = createStore({ count: 5 })
66
62
  const result = toSignal(originalStore)
67
63
 
68
64
  // Runtime behavior
@@ -76,7 +72,7 @@ describe('toSignal', () => {
76
72
  })
77
73
 
78
74
  test('passes through existing State unchanged', () => {
79
- const originalState = state(42)
75
+ const originalState = createState(42)
80
76
  const result = toSignal(originalState)
81
77
 
82
78
  // Runtime behavior
@@ -90,7 +86,7 @@ describe('toSignal', () => {
90
86
  })
91
87
 
92
88
  test('passes through existing Computed unchanged', () => {
93
- const originalComputed = computed(() => 'hello world')
89
+ const originalComputed = createComputed(() => 'hello world')
94
90
  const result = toSignal(originalComputed)
95
91
 
96
92
  // Runtime behavior
@@ -145,11 +141,10 @@ describe('toSignal', () => {
145
141
 
146
142
  describe('edge cases', () => {
147
143
  test('handles nested arrays', () => {
148
- const nestedArr = [
144
+ const result = toSignal([
149
145
  [1, 2],
150
146
  [3, 4],
151
- ]
152
- const result = toSignal(nestedArr)
147
+ ])
153
148
 
154
149
  expect(isStore(result)).toBe(true)
155
150
  // With the fixed behavior, nested arrays should be recovered as arrays
@@ -184,119 +179,13 @@ describe('toSignal', () => {
184
179
  })
185
180
  })
186
181
 
187
- describe('toMutableSignal', () => {
188
- describe('type inference and runtime behavior', () => {
189
- test('converts array to Store<Record<string, T>>', () => {
190
- const arr = [
191
- { id: 1, name: 'Alice' },
192
- { id: 2, name: 'Bob' },
193
- ]
194
- const result = toMutableSignal(arr)
195
-
196
- // Runtime behavior
197
- expect(isStore(result)).toBe(true)
198
- expect(result['0'].get()).toEqual({ id: 1, name: 'Alice' })
199
- expect(result['1'].get()).toEqual({ id: 2, name: 'Bob' })
200
-
201
- // Type inference test - now correctly returns Store<Record<string, {id: number, name: string}>>
202
- const typedResult: Store<
203
- Record<string, { id: number; name: string }>
204
- > = result
205
- expect(typedResult).toBeDefined()
206
- })
207
-
208
- test('converts record to Store<T>', () => {
209
- const record = { name: 'Alice', age: 30 }
210
- const result = toMutableSignal(record)
211
-
212
- // Runtime behavior
213
- expect(isStore(result)).toBe(true)
214
- expect(result.name.get()).toBe('Alice')
215
- expect(result.age.get()).toBe(30)
216
-
217
- // Type inference test - should be Store<{name: string, age: number}>
218
- const typedResult: Store<{ name: string; age: number }> = result
219
- expect(typedResult).toBeDefined()
220
- })
221
-
222
- test('passes through existing Store unchanged', () => {
223
- const originalStore = store({ count: 5 })
224
- const result = toMutableSignal(originalStore)
225
-
226
- // Runtime behavior
227
- expect(result).toBe(originalStore) // Should be the same instance
228
- expect(isStore(result)).toBe(true)
229
- expect(result.count.get()).toBe(5)
230
- })
231
-
232
- test('passes through existing State unchanged', () => {
233
- const originalState = state(42)
234
- const result = toMutableSignal(originalState)
235
-
236
- // Runtime behavior
237
- expect(result).toBe(originalState) // Should be the same instance
238
- expect(isState(result)).toBe(true)
239
- expect(result.get()).toBe(42)
240
-
241
- // Type inference test - should be State<number>
242
- const typedResult: State<number> = result
243
- expect(typedResult).toBeDefined()
244
- })
245
-
246
- test('converts primitive to State<T>', () => {
247
- const num = 42
248
- const result = toMutableSignal(num)
249
-
250
- // Runtime behavior - primitives are correctly converted to State
251
- expect(isState(result)).toBe(true)
252
- expect(result.get()).toBe(42)
253
- })
254
-
255
- test('converts object to State<T> (not Store)', () => {
256
- const obj = new Date('2024-01-01')
257
- const result = toMutableSignal(obj)
258
-
259
- // Runtime behavior - objects are correctly converted to State
260
- expect(isState(result)).toBe(true)
261
- expect(result.get()).toBe(obj)
262
-
263
- // Type inference test - should be State<Date>
264
- const typedResult: State<Date> = result
265
- expect(typedResult).toBeDefined()
266
- })
267
- })
268
-
269
- describe('differences from toSignal', () => {
270
- test('does not accept functions (only mutable signals)', () => {
271
- // toMutableSignal should not have a function overload
272
- // This test documents the expected behavior difference
273
- const fn = () => 'test'
274
- const result = toMutableSignal(fn)
275
-
276
- // Should treat function as a regular value and create State
277
- expect(isState(result)).toBe(true)
278
- expect(result.get()).toBe(fn)
279
- })
280
-
281
- test('does not accept Computed signals', () => {
282
- // toMutableSignal should not accept Computed signals
283
- const comp = computed(() => 'computed value')
284
- const result = toMutableSignal(comp)
285
-
286
- // Should treat Computed as a regular object and create State
287
- expect(isState(result)).toBe(true)
288
- expect(result.get()).toBe(comp)
289
- })
290
- })
291
- })
292
-
293
182
  describe('Signal compatibility', () => {
294
183
  test('all results implement Signal<T> interface', () => {
295
184
  const arraySignal = toSignal([1, 2, 3])
296
185
  const recordSignal = toSignal({ a: 1, b: 2 })
297
186
  const primitiveSignal = toSignal(42)
298
187
  const functionSignal = toSignal(() => 'hello')
299
- const stateSignal = toSignal(state(true))
188
+ const stateSignal = toSignal(createState(true))
300
189
 
301
190
  // All should have get() method
302
191
  expect(typeof arraySignal.get).toBe('function')
@@ -356,14 +245,7 @@ describe('Type precision tests', () => {
356
245
 
357
246
  describe('Type inference issues', () => {
358
247
  test('demonstrates current type inference problem', () => {
359
- // Current issue: when passing an array, T is inferred as the array type
360
- // instead of the element type, causing type compatibility problems
361
- const items = [{ id: 1 }, { id: 2 }]
362
- const result = toSignal(items)
363
-
364
- // This should work but may have type issues in external libraries
365
- // The return type should be Store<Record<string, {id: number}>>
366
- // But currently it might be inferred as Store<Record<string, {id: number}[]>>
248
+ const result = toSignal([{ id: 1 }, { id: 2 }])
367
249
 
368
250
  // Let's verify the actual behavior
369
251
  expect(isStore(result)).toBe(true)
@@ -371,7 +253,7 @@ describe('Type precision tests', () => {
371
253
  expect(result['1'].get()).toEqual({ id: 2 })
372
254
 
373
255
  // Type assertion test - this should now work with correct typing
374
- const typedResult: Store<Record<string, { id: number }>> = result
256
+ const typedResult: Store<{ id: number }[]> = result
375
257
  expect(typedResult).toBeDefined()
376
258
 
377
259
  // Simulate external library usage where P[K] represents element type
@@ -397,19 +279,11 @@ describe('Type precision tests', () => {
397
279
  })
398
280
 
399
281
  test('verifies fixed type inference for external library compatibility', () => {
400
- // This test ensures the fix for the type inference issue works
401
- // Fixed: toSignal<T extends unknown & {}>(value: T[]): Store<Record<string, T>>
402
- // Now T = {id: number} (element type), T[] = {id: number}[] (array of elements)
403
- // Return type: Store<Record<string, {id: number}>> (correct)
404
-
405
282
  const items = [
406
283
  { id: 1, name: 'Alice' },
407
284
  { id: 2, name: 'Bob' },
408
285
  ]
409
286
  const signal = toSignal(items)
410
-
411
- // Type should be Store<Record<string, {id: number, name: string}>>
412
- // Each property signal should be Signal<{id: number, name: string}>
413
287
  const firstItemSignal = signal['0']
414
288
  const secondItemSignal = signal['1']
415
289
 
@@ -419,9 +293,7 @@ describe('Type precision tests', () => {
419
293
  expect(secondItemSignal.get()).toEqual({ id: 2, name: 'Bob' })
420
294
 
421
295
  // Type inference should now work correctly:
422
- const properlyTyped: Store<
423
- Record<string, { id: number; name: string }>
424
- > = signal
296
+ const properlyTyped: Store<{ id: number; name: string }[]> = signal
425
297
  expect(properlyTyped).toBeDefined()
426
298
 
427
299
  // These should work without type errors in external libraries
@@ -1,12 +1,12 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
- import { isComputed, isState, state } from '../'
2
+ import { createState, isComputed, isState } from '../'
3
3
 
4
4
  /* === Tests === */
5
5
 
6
6
  describe('State', () => {
7
7
  describe('State type guard', () => {
8
8
  test('isState identifies state signals', () => {
9
- const count = state(42)
9
+ const count = createState(42)
10
10
  expect(isState(count)).toBe(true)
11
11
  expect(isComputed(count)).toBe(false)
12
12
  })
@@ -14,28 +14,28 @@ describe('State', () => {
14
14
 
15
15
  describe('Boolean cause', () => {
16
16
  test('should be boolean', () => {
17
- const cause = state(false)
17
+ const cause = createState(false)
18
18
  expect(typeof cause.get()).toBe('boolean')
19
19
  })
20
20
 
21
21
  test('should set initial value to false', () => {
22
- const cause = state(false)
22
+ const cause = createState(false)
23
23
  expect(cause.get()).toBe(false)
24
24
  })
25
25
 
26
26
  test('should set initial value to true', () => {
27
- const cause = state(true)
27
+ const cause = createState(true)
28
28
  expect(cause.get()).toBe(true)
29
29
  })
30
30
 
31
31
  test('should set new value with .set(true)', () => {
32
- const cause = state(false)
32
+ const cause = createState(false)
33
33
  cause.set(true)
34
34
  expect(cause.get()).toBe(true)
35
35
  })
36
36
 
37
37
  test('should toggle initial value with .set(v => !v)', () => {
38
- const cause = state(false)
38
+ const cause = createState(false)
39
39
  cause.update(v => !v)
40
40
  expect(cause.get()).toBe(true)
41
41
  })
@@ -43,23 +43,23 @@ describe('State', () => {
43
43
 
44
44
  describe('Number cause', () => {
45
45
  test('should be number', () => {
46
- const cause = state(0)
46
+ const cause = createState(0)
47
47
  expect(typeof cause.get()).toBe('number')
48
48
  })
49
49
 
50
50
  test('should set initial value to 0', () => {
51
- const cause = state(0)
51
+ const cause = createState(0)
52
52
  expect(cause.get()).toBe(0)
53
53
  })
54
54
 
55
55
  test('should set new value with .set(42)', () => {
56
- const cause = state(0)
56
+ const cause = createState(0)
57
57
  cause.set(42)
58
58
  expect(cause.get()).toBe(42)
59
59
  })
60
60
 
61
61
  test('should increment value with .set(v => ++v)', () => {
62
- const cause = state(0)
62
+ const cause = createState(0)
63
63
  cause.update(v => ++v)
64
64
  expect(cause.get()).toBe(1)
65
65
  })
@@ -67,23 +67,23 @@ describe('State', () => {
67
67
 
68
68
  describe('String cause', () => {
69
69
  test('should be string', () => {
70
- const cause = state('foo')
70
+ const cause = createState('foo')
71
71
  expect(typeof cause.get()).toBe('string')
72
72
  })
73
73
 
74
74
  test('should set initial value to "foo"', () => {
75
- const cause = state('foo')
75
+ const cause = createState('foo')
76
76
  expect(cause.get()).toBe('foo')
77
77
  })
78
78
 
79
79
  test('should set new value with .set("bar")', () => {
80
- const cause = state('foo')
80
+ const cause = createState('foo')
81
81
  cause.set('bar')
82
82
  expect(cause.get()).toBe('bar')
83
83
  })
84
84
 
85
85
  test('should upper case value with .set(v => v.toUpperCase())', () => {
86
- const cause = state('foo')
86
+ const cause = createState('foo')
87
87
  cause.update(v => (v ? v.toUpperCase() : ''))
88
88
  expect(cause.get()).toBe('FOO')
89
89
  })
@@ -91,56 +91,243 @@ describe('State', () => {
91
91
 
92
92
  describe('Array cause', () => {
93
93
  test('should be array', () => {
94
- const cause = state([1, 2, 3])
94
+ const cause = createState([1, 2, 3])
95
95
  expect(Array.isArray(cause.get())).toBe(true)
96
96
  })
97
97
 
98
98
  test('should set initial value to [1, 2, 3]', () => {
99
- const cause = state([1, 2, 3])
99
+ const cause = createState([1, 2, 3])
100
100
  expect(cause.get()).toEqual([1, 2, 3])
101
101
  })
102
102
 
103
103
  test('should set new value with .set([4, 5, 6])', () => {
104
- const cause = state([1, 2, 3])
104
+ const cause = createState([1, 2, 3])
105
105
  cause.set([4, 5, 6])
106
106
  expect(cause.get()).toEqual([4, 5, 6])
107
107
  })
108
108
 
109
109
  test('should reflect current value of array after modification', () => {
110
110
  const array = [1, 2, 3]
111
- const cause = state(array)
111
+ const cause = createState(array)
112
112
  array.push(4) // don't do this! the result will be correct, but we can't trigger effects
113
113
  expect(cause.get()).toEqual([1, 2, 3, 4])
114
114
  })
115
115
 
116
116
  test('should set new value with .set([...array, 4])', () => {
117
117
  const array = [1, 2, 3]
118
- const cause = state(array)
118
+ const cause = createState(array)
119
119
  cause.set([...array, 4]) // use destructuring instead!
120
120
  expect(cause.get()).toEqual([1, 2, 3, 4])
121
121
  })
122
+
123
+ describe('Input Validation', () => {
124
+ test('should throw NullishSignalValueError when initialValue is nullish', () => {
125
+ expect(() => {
126
+ // @ts-expect-error - Testing invalid input
127
+ createState(null)
128
+ }).toThrow('Nullish signal values are not allowed in state')
129
+
130
+ expect(() => {
131
+ // @ts-expect-error - Testing invalid input
132
+ createState(undefined)
133
+ }).toThrow('Nullish signal values are not allowed in state')
134
+ })
135
+
136
+ test('should throw NullishSignalValueError when newValue is nullish in set()', () => {
137
+ const state = createState(42)
138
+
139
+ expect(() => {
140
+ // @ts-expect-error - Testing invalid input
141
+ state.set(null)
142
+ }).toThrow('Nullish signal values are not allowed in state')
143
+
144
+ expect(() => {
145
+ // @ts-expect-error - Testing invalid input
146
+ state.set(undefined)
147
+ }).toThrow('Nullish signal values are not allowed in state')
148
+ })
149
+
150
+ test('should throw specific error types for nullish values', () => {
151
+ try {
152
+ // @ts-expect-error - Testing invalid input
153
+ createState(null)
154
+ expect(true).toBe(false) // Should not reach here
155
+ } catch (error) {
156
+ expect(error).toBeInstanceOf(TypeError)
157
+ expect(error.name).toBe('NullishSignalValueError')
158
+ expect(error.message).toBe(
159
+ 'Nullish signal values are not allowed in state',
160
+ )
161
+ }
162
+
163
+ const state = createState(42)
164
+ try {
165
+ // @ts-expect-error - Testing invalid input
166
+ state.set(null)
167
+ expect(true).toBe(false) // Should not reach here
168
+ } catch (error) {
169
+ expect(error).toBeInstanceOf(TypeError)
170
+ expect(error.name).toBe('NullishSignalValueError')
171
+ expect(error.message).toBe(
172
+ 'Nullish signal values are not allowed in state',
173
+ )
174
+ }
175
+ })
176
+
177
+ test('should allow valid non-nullish values', () => {
178
+ // These should not throw
179
+ expect(() => {
180
+ createState(0)
181
+ }).not.toThrow()
182
+
183
+ expect(() => {
184
+ createState('')
185
+ }).not.toThrow()
186
+
187
+ expect(() => {
188
+ createState(false)
189
+ }).not.toThrow()
190
+
191
+ expect(() => {
192
+ createState({})
193
+ }).not.toThrow()
194
+
195
+ expect(() => {
196
+ createState([])
197
+ }).not.toThrow()
198
+
199
+ const state = createState(42)
200
+ expect(() => {
201
+ state.set(0)
202
+ }).not.toThrow()
203
+
204
+ expect(() => {
205
+ // @ts-expect-error - Testing valid input of invalid type
206
+ state.set('')
207
+ }).not.toThrow()
208
+ })
209
+
210
+ test('should throw InvalidCallbackError for non-function updater in update()', () => {
211
+ const state = createState(42)
212
+
213
+ expect(() => {
214
+ // @ts-expect-error - Testing invalid input
215
+ state.update(null)
216
+ }).toThrow('Invalid state update callback null')
217
+
218
+ expect(() => {
219
+ // @ts-expect-error - Testing invalid input
220
+ state.update(undefined)
221
+ }).toThrow('Invalid state update callback undefined')
222
+
223
+ expect(() => {
224
+ // @ts-expect-error - Testing invalid input
225
+ state.update('not a function')
226
+ }).toThrow('Invalid state update callback "not a function"')
227
+
228
+ expect(() => {
229
+ // @ts-expect-error - Testing invalid input
230
+ state.update(42)
231
+ }).toThrow('Invalid state update callback 42')
232
+ })
233
+
234
+ test('should throw specific error type for non-function updater', () => {
235
+ const state = createState(42)
236
+
237
+ try {
238
+ // @ts-expect-error - Testing invalid input
239
+ state.update(null)
240
+ expect(true).toBe(false) // Should not reach here
241
+ } catch (error) {
242
+ expect(error).toBeInstanceOf(TypeError)
243
+ expect(error.name).toBe('InvalidCallbackError')
244
+ expect(error.message).toBe(
245
+ 'Invalid state update callback null',
246
+ )
247
+ }
248
+ })
249
+
250
+ test('should handle updater function that throws an error', () => {
251
+ const state = createState(42)
252
+
253
+ expect(() => {
254
+ state.update(() => {
255
+ throw new Error('Updater error')
256
+ })
257
+ }).toThrow('Updater error')
258
+
259
+ // State should remain unchanged after error
260
+ expect(state.get()).toBe(42)
261
+ })
262
+
263
+ test('should handle updater function that returns nullish value', () => {
264
+ const state = createState(42)
265
+
266
+ expect(() => {
267
+ // @ts-expect-error - Testing invalid return value
268
+ state.update(() => null)
269
+ }).toThrow('Nullish signal values are not allowed in state')
270
+
271
+ expect(() => {
272
+ // @ts-expect-error - Testing invalid return value
273
+ state.update(() => undefined)
274
+ }).toThrow('Nullish signal values are not allowed in state')
275
+
276
+ // State should remain unchanged after error
277
+ expect(state.get()).toBe(42)
278
+ })
279
+
280
+ test('should handle valid updater functions', () => {
281
+ const numberState = createState(10)
282
+ expect(() => {
283
+ numberState.update(x => x + 5)
284
+ }).not.toThrow()
285
+ expect(numberState.get()).toBe(15)
286
+
287
+ const stringState = createState('hello')
288
+ expect(() => {
289
+ stringState.update(x => x.toUpperCase())
290
+ }).not.toThrow()
291
+ expect(stringState.get()).toBe('HELLO')
292
+
293
+ const arrayState = createState([1, 2, 3])
294
+ expect(() => {
295
+ arrayState.update(arr => [...arr, 4])
296
+ }).not.toThrow()
297
+ expect(arrayState.get()).toEqual([1, 2, 3, 4])
298
+
299
+ const objectState = createState({ count: 0 })
300
+ expect(() => {
301
+ objectState.update(obj => ({
302
+ ...obj,
303
+ count: obj.count + 1,
304
+ }))
305
+ }).not.toThrow()
306
+ expect(objectState.get()).toEqual({ count: 1 })
307
+ })
308
+ })
122
309
  })
123
310
 
124
311
  describe('Object cause', () => {
125
312
  test('should be object', () => {
126
- const cause = state({ a: 'a', b: 1 })
313
+ const cause = createState({ a: 'a', b: 1 })
127
314
  expect(typeof cause.get()).toBe('object')
128
315
  })
129
316
 
130
317
  test('should set initial value to { a: "a", b: 1 }', () => {
131
- const cause = state({ a: 'a', b: 1 })
318
+ const cause = createState({ a: 'a', b: 1 })
132
319
  expect(cause.get()).toEqual({ a: 'a', b: 1 })
133
320
  })
134
321
 
135
322
  test('should set new value with .set({ c: true })', () => {
136
- const cause = state<Record<string, unknown>>({ a: 'a', b: 1 })
323
+ const cause = createState<Record<string, unknown>>({ a: 'a', b: 1 })
137
324
  cause.set({ c: true })
138
325
  expect(cause.get()).toEqual({ c: true })
139
326
  })
140
327
 
141
328
  test('should reflect current value of object after modification', () => {
142
329
  const obj = { a: 'a', b: 1 }
143
- const cause = state<Record<string, unknown>>(obj)
330
+ const cause = createState<Record<string, unknown>>(obj)
144
331
  // @ts-expect-error Property 'c' does not exist on type '{ a: string; b: number; }'. (ts 2339)
145
332
  obj.c = true // don't do this! the result will be correct, but we can't trigger effects
146
333
  expect(cause.get()).toEqual({ a: 'a', b: 1, c: true })
@@ -148,7 +335,7 @@ describe('State', () => {
148
335
 
149
336
  test('should set new value with .set({...obj, c: true})', () => {
150
337
  const obj = { a: 'a', b: 1 }
151
- const cause = state<Record<string, unknown>>(obj)
338
+ const cause = createState<Record<string, unknown>>(obj)
152
339
  cause.set({ ...obj, c: true }) // use destructuring instead!
153
340
  expect(cause.get()).toEqual({ a: 'a', b: 1, c: true })
154
341
  })