dev-react-microstore 5.0.0 → 6.0.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.
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Compile-time type tests. Run with: tsc --noEmit
3
+ * Every @ts-expect-error MUST produce an error — if it doesn't, tsc fails.
4
+ * Every other line MUST compile cleanly.
5
+ */
6
+
7
+ import { createStoreState, createSelectorHook } from './index'
8
+
9
+ // ── Test store ──────────────────────────────────────────────────────────────
10
+ const store = createStoreState({
11
+ count: 0,
12
+ name: '',
13
+ user: { firstName: '', lastName: '', age: 0 },
14
+ tags: [] as string[],
15
+ nested: { a: { b: 1 } },
16
+ })
17
+
18
+ // ── get ─────────────────────────────────────────────────────────────────────
19
+ const state = store.get()
20
+ state.count satisfies number
21
+ state.name satisfies string
22
+ state.user satisfies { firstName: string; lastName: string; age: number }
23
+
24
+ // ── getKey ──────────────────────────────────────────────────────────────────
25
+ store.getKey('count') satisfies number
26
+ store.getKey('name') satisfies string
27
+ store.getKey('user') satisfies { firstName: string; lastName: string; age: number }
28
+
29
+ // @ts-expect-error — 'nonexistent' is not a key
30
+ store.getKey('nonexistent')
31
+
32
+ // @ts-expect-error — getKey('count') returns number, not string
33
+ store.getKey('count') satisfies string
34
+
35
+ // ── setKey ──────────────────────────────────────────────────────────────────
36
+ store.setKey('count', 42)
37
+ store.setKey('name', 'hello')
38
+ store.setKey('user', { firstName: 'A', lastName: 'B', age: 1 })
39
+
40
+ // @ts-expect-error — wrong value type for 'count'
41
+ store.setKey('count', 'not a number')
42
+
43
+ // @ts-expect-error — wrong value type for 'name'
44
+ store.setKey('name', 123)
45
+
46
+ // @ts-expect-error — missing required property 'age'
47
+ store.setKey('user', { firstName: 'A', lastName: 'B' })
48
+
49
+ // ── set ─────────────────────────────────────────────────────────────────────
50
+ store.set({ count: 1 })
51
+ store.set({ count: 1, name: 'test' })
52
+
53
+ // @ts-expect-error — wrong type in partial
54
+ store.set({ count: 'oops' })
55
+
56
+ // ── merge (pure read) ──────────────────────────────────────────────────────
57
+ store.merge('user', { age: 31 }) satisfies { firstName: string; lastName: string; age: number }
58
+ store.merge('nested', { a: { b: 2 } }) satisfies { a: { b: number } }
59
+
60
+ // Verify partial — only some keys required
61
+ store.merge('user', { firstName: 'Alice' })
62
+ store.merge('user', {})
63
+
64
+ // @ts-expect-error — 'count' is a primitive, merge should reject
65
+ store.merge('count', 5)
66
+
67
+ // @ts-expect-error — 'name' is a primitive, merge should reject
68
+ store.merge('name', 'test')
69
+
70
+ // @ts-expect-error — wrong property type inside partial
71
+ store.merge('user', { age: 'not a number' })
72
+
73
+ // @ts-expect-error — property doesn't exist on user
74
+ store.merge('user', { nonexistent: true })
75
+
76
+ // ── mergeSet ────────────────────────────────────────────────────────────────
77
+ store.mergeSet('user', { age: 25 })
78
+ store.mergeSet('user', { firstName: 'Bob' })
79
+
80
+ // @ts-expect-error — primitive key
81
+ store.mergeSet('count', 5)
82
+
83
+ // @ts-expect-error — wrong property type
84
+ store.mergeSet('user', { age: 'wrong' })
85
+
86
+ // ── reset ───────────────────────────────────────────────────────────────────
87
+ store.reset()
88
+ store.reset(['count', 'name'])
89
+
90
+ // @ts-expect-error — invalid key
91
+ store.reset(['nonexistent'])
92
+
93
+ // ── batch ───────────────────────────────────────────────────────────────────
94
+ store.batch(() => {
95
+ store.setKey('count', 10)
96
+ store.mergeSet('user', { age: 5 })
97
+ })
98
+
99
+ // ── subscribe ───────────────────────────────────────────────────────────────
100
+ store.subscribe(['count', 'name'], () => {}) satisfies () => void
101
+
102
+ // @ts-expect-error — invalid key in subscribe
103
+ store.subscribe(['nonexistent'], () => {})
104
+
105
+ // ── select ──────────────────────────────────────────────────────────────────
106
+ const picked = store.select(['count', 'name'])
107
+ picked.count satisfies number
108
+ picked.name satisfies string
109
+
110
+ // @ts-expect-error — 'user' not in selection
111
+ picked.user
112
+
113
+ // ── onChange ────────────────────────────────────────────────────────────────
114
+ store.onChange(['count', 'user'], (values, prev) => {
115
+ values.count satisfies number
116
+ values.user satisfies { firstName: string; lastName: string; age: number }
117
+ prev.count satisfies number
118
+ prev.user satisfies { firstName: string; lastName: string; age: number }
119
+ })
120
+
121
+ // ── createSelectorHook ──────────────────────────────────────────────────────
122
+ const useStore = createSelectorHook(store)
123
+
124
+ function TestComponent() {
125
+ const s1 = useStore(['count', 'name'])
126
+ s1.count satisfies number
127
+ s1.name satisfies string
128
+
129
+ const s2 = useStore(['user'])
130
+ s2.user satisfies { firstName: string; lastName: string; age: number }
131
+ }
132
+
133
+ // ── addMiddleware ───────────────────────────────────────────────────────────
134
+ store.addMiddleware((currentState, update, next) => {
135
+ currentState.count satisfies number
136
+ update satisfies Partial<typeof state>
137
+ next()
138
+ })
139
+
140
+ store.addMiddleware((currentState, _update, next) => {
141
+ next({ count: currentState.count + 1 })
142
+ })
143
+
144
+ // ── skipSetWhen / removeSkipSetWhen ─────────────────────────────────────────
145
+ store.skipSetWhen('user', (prev, next) => prev.firstName === next.firstName && prev.age === next.age)
146
+ store.skipSetWhen('count', (prev, next) => prev + 1 === next + 1)
147
+ store.skipSetWhen('tags', (prev, next) => prev.length === next.length && prev.every((t, i) => t === next[i]))
148
+
149
+ // @ts-expect-error — wrong prev/next type in callback
150
+ store.skipSetWhen('count', (prev: string, next: string) => prev === next)
151
+
152
+ // @ts-expect-error — invalid key
153
+ store.skipSetWhen('nonexistent', () => true)
154
+
155
+ store.removeSkipSetWhen('user')
156
+ store.removeSkipSetWhen('count')
157
+
158
+ // @ts-expect-error — invalid key
159
+ store.removeSkipSetWhen('nonexistent')
160
+
161
+ void TestComponent
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: 'jsdom',
6
+ globals: true,
7
+ setupFiles: [],
8
+ exclude: ['src/types.test.ts', '**/node_modules/**', '**/dist/**'],
9
+ },
10
+ })