@oimdb/react 1.1.0 → 1.1.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/README.md +142 -12
- package/dist/index.d.cts +2 -22
- package/dist/index.d.ts +2 -22
- package/package.json +13 -7
package/README.md
CHANGED
|
@@ -108,8 +108,7 @@ For applications with multiple collections, use the React Context pattern for ce
|
|
|
108
108
|
```typescript
|
|
109
109
|
import {
|
|
110
110
|
OIMRICollectionsProvider,
|
|
111
|
-
useOIMCollectionsContext
|
|
112
|
-
StrictCollectionsDictionary
|
|
111
|
+
useOIMCollectionsContext
|
|
113
112
|
} from '@oimdb/react';
|
|
114
113
|
|
|
115
114
|
interface User {
|
|
@@ -140,9 +139,148 @@ function createCollections() {
|
|
|
140
139
|
return { users: usersCollection, teams: teamsCollection } as const;
|
|
141
140
|
}
|
|
142
141
|
|
|
143
|
-
type AppCollections =
|
|
142
|
+
type AppCollections = ReturnType<typeof createCollections>;
|
|
144
143
|
```
|
|
145
144
|
|
|
145
|
+
## TypeScript Typing Strategies
|
|
146
|
+
|
|
147
|
+
For maximum type safety, you should properly type your collections dictionary. There are two main approaches, similar to how Redux handles state typing:
|
|
148
|
+
|
|
149
|
+
### Approach 1: Using `typeof` (Recommended for Simple Cases)
|
|
150
|
+
|
|
151
|
+
The simplest approach is to use TypeScript's `typeof` operator to infer types from your collection instances:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
|
|
155
|
+
|
|
156
|
+
interface User {
|
|
157
|
+
id: string;
|
|
158
|
+
name: string;
|
|
159
|
+
teamId: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface Team {
|
|
163
|
+
id: string;
|
|
164
|
+
name: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Create collections
|
|
168
|
+
const queue = new OIMEventQueue();
|
|
169
|
+
const userTeamIndex = new OIMReactiveIndexManual<string, string>(queue);
|
|
170
|
+
const usersCollection = new OIMRICollection(queue, {
|
|
171
|
+
collectionOpts: { selectPk: (user: User) => user.id },
|
|
172
|
+
indexes: { byTeam: userTeamIndex },
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const teamsCollection = new OIMRICollection(queue, {
|
|
176
|
+
collectionOpts: { selectPk: (team: Team) => team.id },
|
|
177
|
+
indexes: {},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Infer types using typeof
|
|
181
|
+
const collections = {
|
|
182
|
+
users: usersCollection,
|
|
183
|
+
teams: teamsCollection,
|
|
184
|
+
} as const;
|
|
185
|
+
|
|
186
|
+
// Extract the type
|
|
187
|
+
type AppCollections = typeof collections;
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Usage:**
|
|
191
|
+
```typescript
|
|
192
|
+
function MyComponent() {
|
|
193
|
+
const { users, teams } = useOIMCollectionsContext<AppCollections>();
|
|
194
|
+
// users and teams are fully typed with all their generics preserved
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Approach 2: Creating Explicit Types (Recommended for Complex Projects)
|
|
199
|
+
|
|
200
|
+
For larger applications or when you need more control, create explicit type definitions similar to Redux's approach:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
|
|
204
|
+
import type { TOIMPk, OIMIndex, OIMReactiveIndex } from '@oimdb/core';
|
|
205
|
+
|
|
206
|
+
interface User {
|
|
207
|
+
id: string;
|
|
208
|
+
name: string;
|
|
209
|
+
teamId: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface Team {
|
|
213
|
+
id: string;
|
|
214
|
+
name: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Define your collection types explicitly
|
|
218
|
+
type UserCollection = OIMRICollection<
|
|
219
|
+
User,
|
|
220
|
+
string,
|
|
221
|
+
'byTeam',
|
|
222
|
+
string,
|
|
223
|
+
OIMIndex<string, string>,
|
|
224
|
+
OIMReactiveIndex<string, string, OIMIndex<string, string>>
|
|
225
|
+
>;
|
|
226
|
+
|
|
227
|
+
type TeamCollection = OIMRICollection<
|
|
228
|
+
Team,
|
|
229
|
+
string,
|
|
230
|
+
never,
|
|
231
|
+
never,
|
|
232
|
+
OIMIndex<never, never>,
|
|
233
|
+
OIMReactiveIndex<never, never, OIMIndex<never, never>>
|
|
234
|
+
>;
|
|
235
|
+
|
|
236
|
+
// Define your collections dictionary type
|
|
237
|
+
interface AppCollections {
|
|
238
|
+
users: UserCollection;
|
|
239
|
+
teams: TeamCollection;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Factory function that returns properly typed collections
|
|
243
|
+
function createCollections(): AppCollections {
|
|
244
|
+
const queue = new OIMEventQueue();
|
|
245
|
+
const userTeamIndex = new OIMReactiveIndexManual<string, string>(queue);
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
users: new OIMRICollection(queue, {
|
|
249
|
+
collectionOpts: { selectPk: (user: User) => user.id },
|
|
250
|
+
indexes: { byTeam: userTeamIndex },
|
|
251
|
+
}) as UserCollection,
|
|
252
|
+
|
|
253
|
+
teams: new OIMRICollection(queue, {
|
|
254
|
+
collectionOpts: { selectPk: (team: Team) => team.id },
|
|
255
|
+
indexes: {},
|
|
256
|
+
}) as TeamCollection,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Usage:**
|
|
262
|
+
```typescript
|
|
263
|
+
function MyComponent() {
|
|
264
|
+
const { users, teams } = useOIMCollectionsContext<AppCollections>();
|
|
265
|
+
// Full type safety with explicit types
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### When to Use Each Approach
|
|
270
|
+
|
|
271
|
+
- **Use `typeof`** when:
|
|
272
|
+
- You have simple collection setups
|
|
273
|
+
- You want TypeScript to infer everything automatically
|
|
274
|
+
- You prefer less boilerplate
|
|
275
|
+
- Your collections are created in one place
|
|
276
|
+
|
|
277
|
+
- **Use explicit types** when:
|
|
278
|
+
- You need to share types across multiple files
|
|
279
|
+
- You want to document your data structure explicitly
|
|
280
|
+
- You're building a library or shared module
|
|
281
|
+
- You need to ensure type consistency across your application
|
|
282
|
+
- You prefer Redux-style explicit typing patterns
|
|
283
|
+
|
|
146
284
|
### Provider Setup
|
|
147
285
|
|
|
148
286
|
```typescript
|
|
@@ -306,17 +444,9 @@ Creates a custom collections context with specific typing.
|
|
|
306
444
|
|
|
307
445
|
### Type Utilities
|
|
308
446
|
|
|
309
|
-
#### `StrictCollectionsDictionary<T>`
|
|
310
|
-
|
|
311
|
-
Ensures collections dictionary maintains exact types.
|
|
312
|
-
|
|
313
447
|
#### `CollectionsDictionary`
|
|
314
448
|
|
|
315
|
-
Base type for any collections dictionary.
|
|
316
|
-
|
|
317
|
-
#### `ExtractEntityType<T>`, `ExtractPkType<T>`, etc.
|
|
318
|
-
|
|
319
|
-
Type utilities for extracting specific types from collections.
|
|
449
|
+
Base type for any collections dictionary. Use `typeof` to extract types from your collection instances, or define explicit types using `OIMRICollection` generics.
|
|
320
450
|
|
|
321
451
|
## Architecture
|
|
322
452
|
|
package/dist/index.d.cts
CHANGED
|
@@ -10,9 +10,7 @@ declare const useSelectEntitiesByPks: <TEntity extends object, TPk extends TOIMP
|
|
|
10
10
|
declare const useSelectEntitiesByIndexKey: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TEntity[] | null;
|
|
11
11
|
declare const useSelectEntitiesByIndexKeys: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TEntity[] | null;
|
|
12
12
|
|
|
13
|
-
type
|
|
14
|
-
type CollectionsDictionary = Record<string, AnyOIMRICollection>;
|
|
15
|
-
type TypedCollectionsDictionary<T extends CollectionsDictionary> = T;
|
|
13
|
+
type CollectionsDictionary = Record<string, OIMRICollection<object, string, string, string, never, never>>;
|
|
16
14
|
type OIMContextValue<T extends CollectionsDictionary = CollectionsDictionary> = T | null;
|
|
17
15
|
declare const OIMRICollectionsContext: React.Context<OIMContextValue<CollectionsDictionary>>;
|
|
18
16
|
declare function createOIMCollectionsContext<T extends CollectionsDictionary>(): React.Context<OIMContextValue<T>>;
|
|
@@ -23,23 +21,5 @@ interface OIMRICollectionsProviderProps<T extends CollectionsDictionary> {
|
|
|
23
21
|
}
|
|
24
22
|
declare function OIMRICollectionsProvider<T extends CollectionsDictionary>({ collections, children, context, }: OIMRICollectionsProviderProps<T>): react_jsx_runtime.JSX.Element;
|
|
25
23
|
declare function useOIMCollectionsContext<T extends CollectionsDictionary = CollectionsDictionary>(context?: React.Context<OIMContextValue<T>>): T;
|
|
26
|
-
type ExtractEntityType<T> = T extends OIMRICollection<infer E, TOIMPk, string, TOIMPk, any, any> ? E : never;
|
|
27
|
-
type ExtractPkType<T> = T extends OIMRICollection<object, infer P, string, TOIMPk, any, any> ? P : never;
|
|
28
|
-
type ExtractIndexNameType<T> = T extends OIMRICollection<object, TOIMPk, infer IN, TOIMPk, any, any> ? IN : never;
|
|
29
|
-
type ExtractIndexKeyType<T> = T extends OIMRICollection<object, TOIMPk, string, infer IK, any, any> ? IK : never;
|
|
30
|
-
type CreateCollectionsDictionary<T extends Record<string, AnyOIMRICollection>> = {
|
|
31
|
-
[K in keyof T]: T[K];
|
|
32
|
-
};
|
|
33
|
-
type ExtractCollectionSignature<T> = T extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? {
|
|
34
|
-
entity: E;
|
|
35
|
-
pk: P;
|
|
36
|
-
indexName: IN;
|
|
37
|
-
indexKey: IK;
|
|
38
|
-
index: I;
|
|
39
|
-
reactiveIndex: RI;
|
|
40
|
-
} : never;
|
|
41
|
-
type StrictCollectionsDictionary<T> = {
|
|
42
|
-
[K in keyof T]: T[K] extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? OIMRICollection<E, P, IN, IK, I, RI> : never;
|
|
43
|
-
};
|
|
44
24
|
|
|
45
|
-
export { type
|
|
25
|
+
export { type CollectionsDictionary, type OIMContextValue, OIMRICollectionsContext, OIMRICollectionsProvider, type OIMRICollectionsProviderProps, createOIMCollectionsContext, useOIMCollectionsContext, useSelectEntitiesByIndexKey, useSelectEntitiesByIndexKeys, useSelectEntitiesByPks, useSelectEntityByPk, useSelectPksByIndexKey, useSelectPksByIndexKeys };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,9 +10,7 @@ declare const useSelectEntitiesByPks: <TEntity extends object, TPk extends TOIMP
|
|
|
10
10
|
declare const useSelectEntitiesByIndexKey: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TEntity[] | null;
|
|
11
11
|
declare const useSelectEntitiesByIndexKeys: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TEntity[] | null;
|
|
12
12
|
|
|
13
|
-
type
|
|
14
|
-
type CollectionsDictionary = Record<string, AnyOIMRICollection>;
|
|
15
|
-
type TypedCollectionsDictionary<T extends CollectionsDictionary> = T;
|
|
13
|
+
type CollectionsDictionary = Record<string, OIMRICollection<object, string, string, string, never, never>>;
|
|
16
14
|
type OIMContextValue<T extends CollectionsDictionary = CollectionsDictionary> = T | null;
|
|
17
15
|
declare const OIMRICollectionsContext: React.Context<OIMContextValue<CollectionsDictionary>>;
|
|
18
16
|
declare function createOIMCollectionsContext<T extends CollectionsDictionary>(): React.Context<OIMContextValue<T>>;
|
|
@@ -23,23 +21,5 @@ interface OIMRICollectionsProviderProps<T extends CollectionsDictionary> {
|
|
|
23
21
|
}
|
|
24
22
|
declare function OIMRICollectionsProvider<T extends CollectionsDictionary>({ collections, children, context, }: OIMRICollectionsProviderProps<T>): react_jsx_runtime.JSX.Element;
|
|
25
23
|
declare function useOIMCollectionsContext<T extends CollectionsDictionary = CollectionsDictionary>(context?: React.Context<OIMContextValue<T>>): T;
|
|
26
|
-
type ExtractEntityType<T> = T extends OIMRICollection<infer E, TOIMPk, string, TOIMPk, any, any> ? E : never;
|
|
27
|
-
type ExtractPkType<T> = T extends OIMRICollection<object, infer P, string, TOIMPk, any, any> ? P : never;
|
|
28
|
-
type ExtractIndexNameType<T> = T extends OIMRICollection<object, TOIMPk, infer IN, TOIMPk, any, any> ? IN : never;
|
|
29
|
-
type ExtractIndexKeyType<T> = T extends OIMRICollection<object, TOIMPk, string, infer IK, any, any> ? IK : never;
|
|
30
|
-
type CreateCollectionsDictionary<T extends Record<string, AnyOIMRICollection>> = {
|
|
31
|
-
[K in keyof T]: T[K];
|
|
32
|
-
};
|
|
33
|
-
type ExtractCollectionSignature<T> = T extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? {
|
|
34
|
-
entity: E;
|
|
35
|
-
pk: P;
|
|
36
|
-
indexName: IN;
|
|
37
|
-
indexKey: IK;
|
|
38
|
-
index: I;
|
|
39
|
-
reactiveIndex: RI;
|
|
40
|
-
} : never;
|
|
41
|
-
type StrictCollectionsDictionary<T> = {
|
|
42
|
-
[K in keyof T]: T[K] extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? OIMRICollection<E, P, IN, IK, I, RI> : never;
|
|
43
|
-
};
|
|
44
24
|
|
|
45
|
-
export { type
|
|
25
|
+
export { type CollectionsDictionary, type OIMContextValue, OIMRICollectionsContext, OIMRICollectionsProvider, type OIMRICollectionsProviderProps, createOIMCollectionsContext, useOIMCollectionsContext, useSelectEntitiesByIndexKey, useSelectEntitiesByIndexKeys, useSelectEntitiesByPks, useSelectEntityByPk, useSelectPksByIndexKey, useSelectPksByIndexKeys };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oimdb/react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "React integration for OIMDB - Hooks for selection and subscription with external storage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -24,22 +24,28 @@
|
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsup src/index.ts --dts --format esm,cjs",
|
|
27
|
+
"test": "jest",
|
|
28
|
+
"type-check": "tsc --noEmit",
|
|
27
29
|
"clean": "rimraf dist",
|
|
28
|
-
"prepublishOnly": "npm run build"
|
|
30
|
+
"prepublishOnly": "npm run type-check && npm test && npm run build"
|
|
29
31
|
},
|
|
30
32
|
"files": [
|
|
31
33
|
"dist"
|
|
32
34
|
],
|
|
33
35
|
"peerDependencies": {
|
|
34
|
-
"@oimdb/core": "^1.0
|
|
36
|
+
"@oimdb/core": "^1.1.0",
|
|
35
37
|
"react": "^18.0.0"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
40
|
+
"@types/jest": "^29.5.8",
|
|
41
|
+
"@types/react": "^18.0.0",
|
|
42
|
+
"jest": "^29.7.0",
|
|
43
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
41
44
|
"react": "^18.0.0",
|
|
42
|
-
"
|
|
45
|
+
"rimraf": "^5.0.5",
|
|
46
|
+
"ts-jest": "^29.1.1",
|
|
47
|
+
"tsup": "^8.5.0",
|
|
48
|
+
"typescript": "^5.2.2"
|
|
43
49
|
},
|
|
44
50
|
"author": "Andrei Baikov",
|
|
45
51
|
"license": "MIT"
|