@zeix/cause-effect 0.16.0 → 0.17.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 (62) hide show
  1. package/.ai-context.md +71 -21
  2. package/.cursorrules +3 -2
  3. package/.github/copilot-instructions.md +59 -13
  4. package/CLAUDE.md +170 -24
  5. package/LICENSE +1 -1
  6. package/README.md +156 -52
  7. package/archive/benchmark.ts +688 -0
  8. package/archive/collection.ts +312 -0
  9. package/{src → archive}/computed.ts +33 -34
  10. package/archive/list.ts +551 -0
  11. package/archive/memo.ts +138 -0
  12. package/archive/state.ts +89 -0
  13. package/archive/store.ts +368 -0
  14. package/archive/task.ts +194 -0
  15. package/eslint.config.js +1 -0
  16. package/index.dev.js +902 -501
  17. package/index.js +1 -1
  18. package/index.ts +42 -22
  19. package/package.json +1 -1
  20. package/src/classes/collection.ts +272 -0
  21. package/src/classes/composite.ts +176 -0
  22. package/src/classes/computed.ts +333 -0
  23. package/src/classes/list.ts +304 -0
  24. package/src/classes/state.ts +98 -0
  25. package/src/classes/store.ts +210 -0
  26. package/src/diff.ts +28 -52
  27. package/src/effect.ts +9 -9
  28. package/src/errors.ts +50 -25
  29. package/src/signal.ts +58 -41
  30. package/src/system.ts +79 -42
  31. package/src/util.ts +16 -34
  32. package/test/batch.test.ts +15 -17
  33. package/test/benchmark.test.ts +4 -4
  34. package/test/collection.test.ts +796 -0
  35. package/test/computed.test.ts +138 -130
  36. package/test/diff.test.ts +2 -2
  37. package/test/effect.test.ts +36 -35
  38. package/test/list.test.ts +754 -0
  39. package/test/match.test.ts +25 -25
  40. package/test/resolve.test.ts +17 -19
  41. package/test/signal.test.ts +72 -121
  42. package/test/state.test.ts +44 -44
  43. package/test/store.test.ts +344 -1663
  44. package/types/index.d.ts +11 -9
  45. package/types/src/classes/collection.d.ts +32 -0
  46. package/types/src/classes/composite.d.ts +15 -0
  47. package/types/src/classes/computed.d.ts +97 -0
  48. package/types/src/classes/list.d.ts +41 -0
  49. package/types/src/classes/state.d.ts +52 -0
  50. package/types/src/classes/store.d.ts +51 -0
  51. package/types/src/diff.d.ts +8 -12
  52. package/types/src/errors.d.ts +12 -11
  53. package/types/src/signal.d.ts +27 -14
  54. package/types/src/system.d.ts +41 -20
  55. package/types/src/util.d.ts +6 -3
  56. package/src/state.ts +0 -98
  57. package/src/store.ts +0 -525
  58. package/types/src/collection.d.ts +0 -26
  59. package/types/src/computed.d.ts +0 -33
  60. package/types/src/scheduler.d.ts +0 -55
  61. package/types/src/state.d.ts +0 -24
  62. package/types/src/store.d.ts +0 -66
@@ -1,14 +1,15 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import {
3
- createComputed,
4
3
  createEffect,
5
- createState,
6
4
  isComputed,
7
5
  isState,
6
+ Memo,
8
7
  match,
9
8
  resolve,
9
+ State,
10
+ Task,
10
11
  UNSET,
11
- } from '../'
12
+ } from '../index.ts'
12
13
 
13
14
  /* === Utility Functions === */
14
15
 
@@ -19,38 +20,38 @@ const increment = (n: number) => (Number.isFinite(n) ? n + 1 : UNSET)
19
20
 
20
21
  describe('Computed', () => {
21
22
  test('should identify computed signals with isComputed()', () => {
22
- const count = createState(42)
23
- const doubled = createComputed(() => count.get() * 2)
23
+ const count = new State(42)
24
+ const doubled = new Memo(() => count.get() * 2)
24
25
  expect(isComputed(doubled)).toBe(true)
25
26
  expect(isState(doubled)).toBe(false)
26
27
  })
27
28
 
28
29
  test('should compute a function', () => {
29
- const derived = createComputed(() => 1 + 2)
30
+ const derived = new Memo(() => 1 + 2)
30
31
  expect(derived.get()).toBe(3)
31
32
  })
32
33
 
33
34
  test('should compute function dependent on a signal', () => {
34
- const cause = createState(42)
35
- const derived = createComputed(() => cause.get() + 1)
35
+ const cause = new State(42)
36
+ const derived = new Memo(() => cause.get() + 1)
36
37
  expect(derived.get()).toBe(43)
37
38
  })
38
39
 
39
40
  test('should compute function dependent on an updated signal', () => {
40
- const cause = createState(42)
41
- const derived = createComputed(() => cause.get() + 1)
41
+ const cause = new State(42)
42
+ const derived = new Memo(() => cause.get() + 1)
42
43
  cause.set(24)
43
44
  expect(derived.get()).toBe(25)
44
45
  })
45
46
 
46
47
  test('should compute function dependent on an async signal', async () => {
47
- const status = createState('pending')
48
- const promised = createComputed(async () => {
48
+ const status = new State('pending')
49
+ const promised = new Task(async () => {
49
50
  await wait(100)
50
51
  status.set('success')
51
52
  return 42
52
53
  })
53
- const derived = createComputed(() => increment(promised.get()))
54
+ const derived = new Memo(() => increment(promised.get()))
54
55
  expect(derived.get()).toBe(UNSET)
55
56
  expect(status.get()).toBe('pending')
56
57
  await wait(110)
@@ -59,15 +60,15 @@ describe('Computed', () => {
59
60
  })
60
61
 
61
62
  test('should handle errors from an async signal gracefully', async () => {
62
- const status = createState('pending')
63
- const error = createState('')
64
- const promised = createComputed(async () => {
63
+ const status = new State('pending')
64
+ const error = new State('')
65
+ const promised = new Task(async () => {
65
66
  await wait(100)
66
67
  status.set('error')
67
68
  error.set('error occurred')
68
69
  return 0
69
70
  })
70
- const derived = createComputed(() => increment(promised.get()))
71
+ const derived = new Memo(() => increment(promised.get()))
71
72
  expect(derived.get()).toBe(UNSET)
72
73
  expect(status.get()).toBe('pending')
73
74
  await wait(110)
@@ -76,15 +77,15 @@ describe('Computed', () => {
76
77
  })
77
78
 
78
79
  test('should compute task signals in parallel without waterfalls', async () => {
79
- const a = createComputed(async () => {
80
+ const a = new Task(async () => {
80
81
  await wait(100)
81
82
  return 10
82
83
  })
83
- const b = createComputed(async () => {
84
+ const b = new Task(async () => {
84
85
  await wait(100)
85
86
  return 20
86
87
  })
87
- const c = createComputed(() => {
88
+ const c = new Memo(() => {
88
89
  const aValue = a.get()
89
90
  const bValue = b.get()
90
91
  return aValue === UNSET || bValue === UNSET
@@ -97,28 +98,28 @@ describe('Computed', () => {
97
98
  })
98
99
 
99
100
  test('should compute function dependent on a chain of computed states dependent on a signal', () => {
100
- const x = createState(42)
101
- const a = createComputed(() => x.get() + 1)
102
- const b = createComputed(() => a.get() * 2)
103
- const c = createComputed(() => b.get() + 1)
101
+ const x = new State(42)
102
+ const a = new Memo(() => x.get() + 1)
103
+ const b = new Memo(() => a.get() * 2)
104
+ const c = new Memo(() => b.get() + 1)
104
105
  expect(c.get()).toBe(87)
105
106
  })
106
107
 
107
108
  test('should compute function dependent on a chain of computed states dependent on an updated signal', () => {
108
- const x = createState(42)
109
- const a = createComputed(() => x.get() + 1)
110
- const b = createComputed(() => a.get() * 2)
111
- const c = createComputed(() => b.get() + 1)
109
+ const x = new State(42)
110
+ const a = new Memo(() => x.get() + 1)
111
+ const b = new Memo(() => a.get() * 2)
112
+ const c = new Memo(() => b.get() + 1)
112
113
  x.set(24)
113
114
  expect(c.get()).toBe(51)
114
115
  })
115
116
 
116
117
  test('should drop X->B->X updates', () => {
117
118
  let count = 0
118
- const x = createState(2)
119
- const a = createComputed(() => x.get() - 1)
120
- const b = createComputed(() => x.get() + a.get())
121
- const c = createComputed(() => {
119
+ const x = new State(2)
120
+ const a = new Memo(() => x.get() - 1)
121
+ const b = new Memo(() => x.get() + a.get())
122
+ const c = new Memo(() => {
122
123
  count++
123
124
  return `c: ${b.get()}`
124
125
  })
@@ -131,10 +132,10 @@ describe('Computed', () => {
131
132
 
132
133
  test('should only update every signal once (diamond graph)', () => {
133
134
  let count = 0
134
- const x = createState('a')
135
- const a = createComputed(() => x.get())
136
- const b = createComputed(() => x.get())
137
- const c = createComputed(() => {
135
+ const x = new State('a')
136
+ const a = new Memo(() => x.get())
137
+ const b = new Memo(() => x.get())
138
+ const c = new Memo(() => {
138
139
  count++
139
140
  return `${a.get()} ${b.get()}`
140
141
  })
@@ -148,11 +149,11 @@ describe('Computed', () => {
148
149
 
149
150
  test('should only update every signal once (diamond graph + tail)', () => {
150
151
  let count = 0
151
- const x = createState('a')
152
- const a = createComputed(() => x.get())
153
- const b = createComputed(() => x.get())
154
- const c = createComputed(() => `${a.get()} ${b.get()}`)
155
- const d = createComputed(() => {
152
+ const x = new State('a')
153
+ const a = new Memo(() => x.get())
154
+ const b = new Memo(() => x.get())
155
+ const c = new Memo(() => `${a.get()} ${b.get()}`)
156
+ const d = new Memo(() => {
156
157
  count++
157
158
  return c.get()
158
159
  })
@@ -164,10 +165,10 @@ describe('Computed', () => {
164
165
  })
165
166
 
166
167
  test('should update multiple times after multiple state changes', () => {
167
- const a = createState(3)
168
- const b = createState(4)
168
+ const a = new State(3)
169
+ const b = new State(4)
169
170
  let count = 0
170
- const sum = createComputed(() => {
171
+ const sum = new Memo(() => {
171
172
  count++
172
173
  return a.get() + b.get()
173
174
  })
@@ -189,12 +190,12 @@ describe('Computed', () => {
189
190
  */
190
191
  test('should bail out if result is the same', () => {
191
192
  let count = 0
192
- const x = createState('a')
193
- const a = createComputed(() => {
193
+ const x = new State('a')
194
+ const a = new Memo(() => {
194
195
  x.get()
195
196
  return 'foo'
196
197
  })
197
- const b = createComputed(() => {
198
+ const b = new Memo(() => {
198
199
  count++
199
200
  return a.get()
200
201
  })
@@ -209,10 +210,10 @@ describe('Computed', () => {
209
210
 
210
211
  test('should block if result remains unchanged', () => {
211
212
  let count = 0
212
- const x = createState(42)
213
- const a = createComputed(() => x.get() % 2)
214
- const b = createComputed(() => (a.get() ? 'odd' : 'even'))
215
- const c = createComputed(() => {
213
+ const x = new State(42)
214
+ const a = new Memo(() => x.get() % 2)
215
+ const b = new Memo(() => (a.get() ? 'odd' : 'even'))
216
+ const c = new Memo(() => {
216
217
  count++
217
218
  return `c: ${b.get()}`
218
219
  })
@@ -226,26 +227,26 @@ describe('Computed', () => {
226
227
  })
227
228
 
228
229
  test('should detect and throw error for circular dependencies', () => {
229
- const a = createState(1)
230
- const b = createComputed(() => c.get() + 1)
231
- const c = createComputed(() => b.get() + a.get())
230
+ const a = new State(1)
231
+ const b = new Memo(() => c.get() + 1)
232
+ const c = new Memo(() => b.get() + a.get())
232
233
  expect(() => {
233
234
  b.get() // This should trigger the circular dependency
234
- }).toThrow('Circular dependency detected in computed')
235
+ }).toThrow('Circular dependency detected in memo')
235
236
  expect(a.get()).toBe(1)
236
237
  })
237
238
 
238
239
  test('should propagate error if an error occurred', () => {
239
240
  let okCount = 0
240
241
  let errCount = 0
241
- const x = createState(0)
242
- const a = createComputed(() => {
242
+ const x = new State(0)
243
+ const a = new Memo(() => {
243
244
  if (x.get() === 1) throw new Error('Calculation error')
244
245
  return 1
245
246
  })
246
247
 
247
248
  // Replace matcher with try/catch in a computed
248
- const b = createComputed(() => {
249
+ const b = new Memo(() => {
249
250
  try {
250
251
  a.get() // just check if it works
251
252
  return `c: success`
@@ -254,7 +255,7 @@ describe('Computed', () => {
254
255
  return `c: recovered`
255
256
  }
256
257
  })
257
- const c = createComputed(() => {
258
+ const c = new Memo(() => {
258
259
  okCount++
259
260
  return b.get()
260
261
  })
@@ -276,8 +277,8 @@ describe('Computed', () => {
276
277
  })
277
278
 
278
279
  test('should create an effect that reacts on async computed changes', async () => {
279
- const cause = createState(42)
280
- const derived = createComputed(async () => {
280
+ const cause = new State(42)
281
+ const derived = new Task(async () => {
281
282
  await wait(100)
282
283
  return cause.get() + 1
283
284
  })
@@ -308,12 +309,12 @@ describe('Computed', () => {
308
309
  })
309
310
 
310
311
  test('should handle complex computed signal with error and async dependencies', async () => {
311
- const toggleState = createState(true)
312
- const errorProne = createComputed(() => {
312
+ const toggleState = new State(true)
313
+ const errorProne = new Memo(() => {
313
314
  if (toggleState.get()) throw new Error('Intentional error')
314
315
  return 42
315
316
  })
316
- const asyncValue = createComputed(async () => {
317
+ const asyncValue = new Task(async () => {
317
318
  await wait(50)
318
319
  return 10
319
320
  })
@@ -322,7 +323,7 @@ describe('Computed', () => {
322
323
  let errCount = 0
323
324
  // let _result: number = 0
324
325
 
325
- const complexComputed = createComputed(() => {
326
+ const complexComputed = new Memo(() => {
326
327
  try {
327
328
  const x = errorProne.get()
328
329
  const y = asyncValue.get()
@@ -355,9 +356,9 @@ describe('Computed', () => {
355
356
  })
356
357
 
357
358
  test('should handle signal changes during async computation', async () => {
358
- const source = createState(1)
359
+ const source = new State(1)
359
360
  let computationCount = 0
360
- const derived = createComputed(async (_, abort) => {
361
+ const derived = new Task(async (_, abort) => {
361
362
  computationCount++
362
363
  expect(abort?.aborted).toBe(false)
363
364
  await wait(100)
@@ -376,9 +377,9 @@ describe('Computed', () => {
376
377
  })
377
378
 
378
379
  test('should handle multiple rapid changes during async computation', async () => {
379
- const source = createState(1)
380
+ const source = new State(1)
380
381
  let computationCount = 0
381
- const derived = createComputed(async (_, abort) => {
382
+ const derived = new Task(async (_, abort) => {
382
383
  computationCount++
383
384
  expect(abort?.aborted).toBe(false)
384
385
  await wait(100)
@@ -401,8 +402,8 @@ describe('Computed', () => {
401
402
  })
402
403
 
403
404
  test('should handle errors in aborted computations', async () => {
404
- const source = createState(1)
405
- const derived = createComputed(async () => {
405
+ const source = new State(1)
406
+ const derived = new Task(async () => {
406
407
  await wait(100)
407
408
  const value = source.get()
408
409
  if (value === 2) throw new Error('Intentional error')
@@ -427,62 +428,72 @@ describe('Computed', () => {
427
428
  test('should throw InvalidCallbackError when callback is not a function', () => {
428
429
  expect(() => {
429
430
  // @ts-expect-error - Testing invalid input
430
- createComputed(null)
431
- }).toThrow('Invalid computed callback null')
431
+ new Memo(null)
432
+ }).toThrow('Invalid memo callback null')
432
433
 
433
434
  expect(() => {
434
435
  // @ts-expect-error - Testing invalid input
435
- createComputed(undefined)
436
- }).toThrow('Invalid computed callback undefined')
436
+ new Memo(undefined)
437
+ }).toThrow('Invalid memo callback undefined')
437
438
 
438
439
  expect(() => {
439
440
  // @ts-expect-error - Testing invalid input
440
- createComputed(42)
441
- }).toThrow('Invalid computed callback 42')
441
+ new Memo(42)
442
+ }).toThrow('Invalid memo callback 42')
442
443
 
443
444
  expect(() => {
444
445
  // @ts-expect-error - Testing invalid input
445
- createComputed('not a function')
446
- }).toThrow('Invalid computed callback "not a function"')
446
+ new Memo('not a function')
447
+ }).toThrow('Invalid memo callback "not a function"')
447
448
 
448
449
  expect(() => {
449
450
  // @ts-expect-error - Testing invalid input
450
- createComputed({ not: 'a function' })
451
- }).toThrow('Invalid computed callback {"not":"a function"}')
451
+ new Memo({ not: 'a function' })
452
+ }).toThrow('Invalid memo callback {"not":"a function"}')
452
453
 
453
454
  expect(() => {
454
455
  // @ts-expect-error - Testing invalid input
455
- createComputed((_a: unknown, _b: unknown, _c: unknown) => 42)
456
- }).toThrow('Invalid computed callback (_a, _b, _c) => 42')
456
+ new Memo((_a: unknown, _b: unknown, _c: unknown) => 42)
457
+ }).toThrow('Invalid memo callback (_a, _b, _c) => 42')
458
+
459
+ expect(() => {
460
+ // @ts-expect-error - Testing invalid input
461
+ new Memo(async (_a: unknown, _b: unknown) => 42)
462
+ }).toThrow('Invalid memo callback async (_a, _b) => 42')
463
+
464
+ expect(() => {
465
+ // @ts-expect-error - Testing invalid input
466
+ new Task((_a: unknown) => 42)
467
+ }).toThrow('Invalid task callback (_a) => 42')
457
468
  })
458
469
 
459
470
  test('should throw NullishSignalValueError when initialValue is null', () => {
460
471
  expect(() => {
461
472
  // @ts-expect-error - Testing invalid input
462
- createComputed(() => 42, null)
463
- }).toThrow('Nullish signal values are not allowed in computed')
473
+ new Memo(() => 42, null)
474
+ }).toThrow('Nullish signal values are not allowed in memo')
464
475
  })
465
476
 
466
477
  test('should throw specific error types for invalid inputs', () => {
467
478
  try {
468
479
  // @ts-expect-error - Testing invalid input
469
- createComputed(null)
480
+ new Memo(null)
470
481
  expect(true).toBe(false) // Should not reach here
471
482
  } catch (error) {
472
483
  expect(error).toBeInstanceOf(TypeError)
473
484
  expect(error.name).toBe('InvalidCallbackError')
474
- expect(error.message).toBe('Invalid computed callback null')
485
+ expect(error.message).toBe('Invalid memo callback null')
475
486
  }
476
487
 
477
488
  try {
478
489
  // @ts-expect-error - Testing invalid input
479
- createComputed(() => 42, null)
490
+ new Memo(() => 42, null)
480
491
  expect(true).toBe(false) // Should not reach here
481
492
  } catch (error) {
482
493
  expect(error).toBeInstanceOf(TypeError)
483
494
  expect(error.name).toBe('NullishSignalValueError')
484
495
  expect(error.message).toBe(
485
- 'Nullish signal values are not allowed in computed',
496
+ 'Nullish signal values are not allowed in memo',
486
497
  )
487
498
  }
488
499
  })
@@ -490,40 +501,37 @@ describe('Computed', () => {
490
501
  test('should allow valid callbacks and non-nullish initialValues', () => {
491
502
  // These should not throw
492
503
  expect(() => {
493
- createComputed(() => 42)
504
+ new Memo(() => 42)
494
505
  }).not.toThrow()
495
506
 
496
507
  expect(() => {
497
- createComputed(() => 42, 0)
508
+ new Memo(() => 42, 0)
498
509
  }).not.toThrow()
499
510
 
500
511
  expect(() => {
501
- createComputed(() => 'foo', '')
512
+ new Memo(() => 'foo', '')
502
513
  }).not.toThrow()
503
514
 
504
515
  expect(() => {
505
- createComputed(() => true, false)
516
+ new Memo(() => true, false)
506
517
  }).not.toThrow()
507
518
 
508
519
  expect(() => {
509
- createComputed(async () => ({ id: 42, name: 'John' }), UNSET)
520
+ new Task(async () => ({ id: 42, name: 'John' }), UNSET)
510
521
  }).not.toThrow()
511
522
  })
512
523
  })
513
524
 
514
525
  describe('Initial Value and Old Value', () => {
515
526
  test('should use initialValue when provided', () => {
516
- const computed = createComputed(
517
- (oldValue: number) => oldValue + 1,
518
- 10,
519
- )
527
+ const computed = new Memo((oldValue: number) => oldValue + 1, 10)
520
528
  expect(computed.get()).toBe(11)
521
529
  })
522
530
 
523
531
  test('should pass current value as oldValue to callback', () => {
524
- const state = createState(5)
532
+ const state = new State(5)
525
533
  let receivedOldValue: number | undefined
526
- const computed = createComputed((oldValue: number) => {
534
+ const computed = new Memo((oldValue: number) => {
527
535
  receivedOldValue = oldValue
528
536
  return state.get() * 2
529
537
  }, 0)
@@ -537,8 +545,8 @@ describe('Computed', () => {
537
545
  })
538
546
 
539
547
  test('should work as reducer function with oldValue', () => {
540
- const increment = createState(0)
541
- const sum = createComputed((oldValue: number) => {
548
+ const increment = new State(0)
549
+ const sum = new Memo((oldValue: number) => {
542
550
  const inc = increment.get()
543
551
  return inc === 0 ? oldValue : oldValue + inc
544
552
  }, 0)
@@ -556,8 +564,8 @@ describe('Computed', () => {
556
564
  })
557
565
 
558
566
  test('should handle array accumulation with oldValue', () => {
559
- const item = createState('')
560
- const items = createComputed((oldValue: string[]) => {
567
+ const item = new State('')
568
+ const items = new Memo((oldValue: string[]) => {
561
569
  const newItem = item.get()
562
570
  return newItem === '' ? oldValue : [...oldValue, newItem]
563
571
  }, [] as string[])
@@ -575,9 +583,9 @@ describe('Computed', () => {
575
583
  })
576
584
 
577
585
  test('should handle counter with oldValue and multiple dependencies', () => {
578
- const reset = createState(false)
579
- const add = createState(0)
580
- const counter = createComputed((oldValue: number) => {
586
+ const reset = new State(false)
587
+ const add = new State(0)
588
+ const counter = new Memo((oldValue: number) => {
581
589
  if (reset.get()) return 0
582
590
  const increment = add.get()
583
591
  return increment === 0 ? oldValue : oldValue + increment
@@ -601,8 +609,8 @@ describe('Computed', () => {
601
609
 
602
610
  test('should pass UNSET as oldValue when no initialValue provided', () => {
603
611
  let receivedOldValue: number | undefined
604
- const state = createState(42)
605
- const computed = createComputed((oldValue: number) => {
612
+ const state = new State(42)
613
+ const computed = new Memo((oldValue: number) => {
606
614
  receivedOldValue = oldValue
607
615
  return state.get()
608
616
  })
@@ -614,7 +622,7 @@ describe('Computed', () => {
614
622
  test('should work with async computation and oldValue', async () => {
615
623
  let receivedOldValue: number | undefined
616
624
 
617
- const asyncComputed = createComputed(async (oldValue: number) => {
625
+ const asyncComputed = new Task(async (oldValue: number) => {
618
626
  receivedOldValue = oldValue
619
627
  await wait(50)
620
628
  return oldValue + 5
@@ -630,9 +638,9 @@ describe('Computed', () => {
630
638
  })
631
639
 
632
640
  test('should handle object updates with oldValue', () => {
633
- const key = createState('')
634
- const value = createState('')
635
- const obj = createComputed(
641
+ const key = new State('')
642
+ const value = new State('')
643
+ const obj = new Memo(
636
644
  (oldValue: Record<string, string>) => {
637
645
  const k = key.get()
638
646
  const v = value.get()
@@ -654,11 +662,11 @@ describe('Computed', () => {
654
662
  })
655
663
 
656
664
  test('should handle async computation with AbortSignal and oldValue', async () => {
657
- const source = createState(1)
665
+ const source = new State(1)
658
666
  let computationCount = 0
659
667
  const receivedOldValues: number[] = []
660
668
 
661
- const asyncComputed = createComputed(
669
+ const asyncComputed = new Task(
662
670
  async (oldValue: number, abort: AbortSignal) => {
663
671
  computationCount++
664
672
  receivedOldValues.push(oldValue)
@@ -692,10 +700,10 @@ describe('Computed', () => {
692
700
  })
693
701
 
694
702
  test('should work with error handling and oldValue', () => {
695
- const shouldError = createState(false)
696
- const counter = createState(1)
703
+ const shouldError = new State(false)
704
+ const counter = new State(1)
697
705
 
698
- const computed = createComputed((oldValue: number) => {
706
+ const computed = new Memo((oldValue: number) => {
699
707
  if (shouldError.get()) {
700
708
  throw new Error('Computation failed')
701
709
  }
@@ -722,12 +730,12 @@ describe('Computed', () => {
722
730
  })
723
731
 
724
732
  test('should work with complex state transitions using oldValue', () => {
725
- const action = createState<
733
+ const action = new State<
726
734
  'increment' | 'decrement' | 'reset' | 'multiply'
727
735
  >('increment')
728
- const amount = createState(1)
736
+ const amount = new State(1)
729
737
 
730
- const calculator = createComputed((oldValue: number) => {
738
+ const calculator = new Memo((oldValue: number) => {
731
739
  const act = action.get()
732
740
  const amt = amount.get()
733
741
 
@@ -764,7 +772,7 @@ describe('Computed', () => {
764
772
 
765
773
  test('should handle edge cases with initialValue and oldValue', () => {
766
774
  // Test with null/undefined-like values
767
- const nullishComputed = createComputed((oldValue: string) => {
775
+ const nullishComputed = new Memo((oldValue: string) => {
768
776
  return `${oldValue} updated`
769
777
  }, '')
770
778
 
@@ -778,7 +786,7 @@ describe('Computed', () => {
778
786
  }
779
787
 
780
788
  const now = new Date()
781
- const objectComputed = createComputed(
789
+ const objectComputed = new Memo(
782
790
  (oldValue: StateObject) => ({
783
791
  ...oldValue,
784
792
  count: oldValue.count + 1,
@@ -799,14 +807,14 @@ describe('Computed', () => {
799
807
 
800
808
  test('should preserve initialValue type consistency', () => {
801
809
  // Test that oldValue type is consistent with initialValue
802
- const stringComputed = createComputed((oldValue: string) => {
810
+ const stringComputed = new Memo((oldValue: string) => {
803
811
  expect(typeof oldValue).toBe('string')
804
812
  return oldValue.toUpperCase()
805
813
  }, 'hello')
806
814
 
807
815
  expect(stringComputed.get()).toBe('HELLO')
808
816
 
809
- const numberComputed = createComputed((oldValue: number) => {
817
+ const numberComputed = new Memo((oldValue: number) => {
810
818
  expect(typeof oldValue).toBe('number')
811
819
  expect(Number.isFinite(oldValue)).toBe(true)
812
820
  return oldValue * 2
@@ -816,14 +824,14 @@ describe('Computed', () => {
816
824
  })
817
825
 
818
826
  test('should work with chained computed using oldValue', () => {
819
- const source = createState(1)
827
+ const source = new State(1)
820
828
 
821
- const first = createComputed(
829
+ const first = new Memo(
822
830
  (oldValue: number) => oldValue + source.get(),
823
831
  10,
824
832
  )
825
833
 
826
- const second = createComputed(
834
+ const second = new Memo(
827
835
  (oldValue: number) => oldValue + first.get(),
828
836
  20,
829
837
  )
@@ -837,10 +845,10 @@ describe('Computed', () => {
837
845
  })
838
846
 
839
847
  test('should handle frequent updates with oldValue correctly', () => {
840
- const trigger = createState(0)
848
+ const trigger = new State(0)
841
849
  let computationCount = 0
842
850
 
843
- const accumulator = createComputed((oldValue: number) => {
851
+ const accumulator = new Memo((oldValue: number) => {
844
852
  computationCount++
845
853
  return oldValue + trigger.get()
846
854
  }, 100)
package/test/diff.test.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  isEqual,
6
6
  UNSET,
7
7
  type UnknownRecord,
8
- } from '..'
8
+ } from '../index.ts'
9
9
 
10
10
  describe('diff', () => {
11
11
  describe('basic object diffing', () => {
@@ -379,7 +379,7 @@ describe('diff', () => {
379
379
  type OptionalKeysType = {
380
380
  required: string
381
381
  optional?: number
382
- maybeUndefined?: string | undefined
382
+ maybeUndefined?: string
383
383
  }
384
384
 
385
385
  test('should handle optional keys correctly', () => {