Skip to content

Commit ccd00a3

Browse files
committed
Merge branch 'VickyStash/bugfix/update-eviction-rules' into VickyStash/test-reassure
2 parents 36da927 + 447f9e3 commit ccd00a3

18 files changed

+218
-81
lines changed

.eslintignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
*.d.ts
22
dist
33
node_modules
4-
*.config.js
4+
*.config.js
5+
# tests/types catalog is not type checked with the rest of the project, so we need to ignore it in eslint
6+
tests/types/**/*.ts

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ jobs:
3030
- run: npm run test
3131
env:
3232
CI: true
33+
34+
- run: npm run test:types

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module.exports = {
44
transform: {
55
'\\.[jt]sx?$': 'babel-jest',
66
},
7-
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/tests/unit/mocks/', '<rootDir>/tests/e2e/'],
7+
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/tests/unit/mocks/', '<rootDir>/tests/e2e/', '<rootDir>/tests/types/'],
88
testMatch: ['**/tests/unit/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
99
globals: {
1010
__DEV__: true,

lib/Onyx.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import Storage from './storage';
44
import utils from './utils';
55
import DevTools, {initDevTools} from './DevTools';
66
import type {
7-
Collection,
8-
CollectionKey,
97
CollectionKeyBase,
108
ConnectOptions,
119
InitOptions,
@@ -15,6 +13,7 @@ import type {
1513
MixedOperationsQueue,
1614
OnyxKey,
1715
OnyxMergeCollectionInput,
16+
OnyxSetCollectionInput,
1817
OnyxMergeInput,
1918
OnyxMultiSetInput,
2019
OnyxSetInput,
@@ -270,7 +269,7 @@ function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>):
270269
* @param collectionKey e.g. `ONYXKEYS.COLLECTION.REPORT`
271270
* @param collection Object collection keyed by individual collection member keys and values
272271
*/
273-
function mergeCollection<TKey extends CollectionKeyBase, TMap>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TKey, TMap>): Promise<void> {
272+
function mergeCollection<TKey extends CollectionKeyBase>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TKey>): Promise<void> {
274273
return OnyxUtils.mergeCollectionWithPatches({collectionKey, collection, isProcessingCollectionUpdate: true});
275274
}
276275

@@ -441,7 +440,7 @@ function update(data: OnyxUpdate[]): Promise<void> {
441440
[OnyxUtils.METHOD.SET]: enqueueSetOperation,
442441
[OnyxUtils.METHOD.MERGE]: enqueueMergeOperation,
443442
[OnyxUtils.METHOD.MERGE_COLLECTION]: () => {
444-
const collection = value as Collection<CollectionKey, unknown, unknown>;
443+
const collection = value as OnyxMergeCollectionInput<OnyxKey>;
445444
if (!OnyxUtils.isValidNonEmptyCollectionForMerge(collection)) {
446445
Logger.logInfo('mergeCollection enqueued within update() with invalid or empty value. Skipping this operation.');
447446
return;
@@ -454,7 +453,7 @@ function update(data: OnyxUpdate[]): Promise<void> {
454453
collectionKeys.forEach((collectionKey) => enqueueMergeOperation(collectionKey, mergedCollection[collectionKey]));
455454
}
456455
},
457-
[OnyxUtils.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k, v as Collection<CollectionKey, unknown, unknown>)),
456+
[OnyxUtils.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k, v as OnyxSetCollectionInput<OnyxKey>)),
458457
[OnyxUtils.METHOD.MULTI_SET]: (k, v) => Object.entries(v as Partial<OnyxInputKeyValueMapping>).forEach(([entryKey, entryValue]) => enqueueSetOperation(entryKey, entryValue)),
459458
[OnyxUtils.METHOD.CLEAR]: () => {
460459
clearPromise = clear();
@@ -507,14 +506,14 @@ function update(data: OnyxUpdate[]): Promise<void> {
507506
promises.push(() =>
508507
OnyxUtils.mergeCollectionWithPatches({
509508
collectionKey,
510-
collection: batchedCollectionUpdates.merge as Collection<CollectionKey, unknown, unknown>,
509+
collection: batchedCollectionUpdates.merge as OnyxMergeCollectionInput<OnyxKey>,
511510
mergeReplaceNullPatches: batchedCollectionUpdates.mergeReplaceNullPatches,
512511
isProcessingCollectionUpdate: true,
513512
}),
514513
);
515514
}
516515
if (!utils.isEmptyObject(batchedCollectionUpdates.set)) {
517-
promises.push(() => OnyxUtils.partialSetCollection({collectionKey, collection: batchedCollectionUpdates.set as Collection<CollectionKey, unknown, unknown>}));
516+
promises.push(() => OnyxUtils.partialSetCollection({collectionKey, collection: batchedCollectionUpdates.set as OnyxSetCollectionInput<OnyxKey>}));
518517
}
519518
});
520519

@@ -551,7 +550,7 @@ function update(data: OnyxUpdate[]): Promise<void> {
551550
* @param collectionKey e.g. `ONYXKEYS.COLLECTION.REPORT`
552551
* @param collection Object collection keyed by individual collection member keys and values
553552
*/
554-
function setCollection<TKey extends CollectionKeyBase, TMap>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TKey, TMap>): Promise<void> {
553+
function setCollection<TKey extends CollectionKeyBase>(collectionKey: TKey, collection: OnyxSetCollectionInput<TKey>): Promise<void> {
555554
return OnyxUtils.setCollectionWithRetry({collectionKey, collection});
556555
}
557556

lib/OnyxUtils.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,7 @@ function initializeWithDefaultKeyStates(): Promise<void> {
11271127
/**
11281128
* Validate the collection is not empty and has a correct type before applying mergeCollection()
11291129
*/
1130-
function isValidNonEmptyCollectionForMerge<TKey extends CollectionKeyBase, TMap>(collection: OnyxMergeCollectionInput<TKey, TMap>): boolean {
1130+
function isValidNonEmptyCollectionForMerge<TKey extends CollectionKeyBase>(collection: OnyxMergeCollectionInput<TKey>): boolean {
11311131
return typeof collection === 'object' && !Array.isArray(collection) && !utils.isEmptyObject(collection);
11321132
}
11331133

@@ -1360,6 +1360,7 @@ function setWithRetry<TKey extends OnyxKey>({key, value, options}: SetParams<TKe
13601360
}
13611361

13621362
const existingValue = cache.get(key, false);
1363+
13631364
// If the existing value as well as the new value are null, we can return early.
13641365
if (existingValue === undefined && value === null) {
13651366
return Promise.resolve();
@@ -1463,7 +1464,7 @@ function multiSetWithRetry(data: OnyxMultiSetInput, retryAttempt?: number): Prom
14631464
* @param params.collection Object collection keyed by individual collection member keys and values
14641465
* @param retryAttempt retry attempt
14651466
*/
1466-
function setCollectionWithRetry<TKey extends CollectionKeyBase, TMap>({collectionKey, collection}: SetCollectionParams<TKey, TMap>, retryAttempt?: number): Promise<void> {
1467+
function setCollectionWithRetry<TKey extends CollectionKeyBase>({collectionKey, collection}: SetCollectionParams<TKey>, retryAttempt?: number): Promise<void> {
14671468
let resultCollection: OnyxInputKeyValueMapping = collection;
14681469
let resultCollectionKeys = Object.keys(resultCollection);
14691470

@@ -1535,8 +1536,8 @@ function setCollectionWithRetry<TKey extends CollectionKeyBase, TMap>({collectio
15351536
* @param params.isProcessingCollectionUpdate whether this is part of a collection update operation.
15361537
* @param retryAttempt retry attempt
15371538
*/
1538-
function mergeCollectionWithPatches<TKey extends CollectionKeyBase, TMap>(
1539-
{collectionKey, collection, mergeReplaceNullPatches, isProcessingCollectionUpdate = false}: MergeCollectionWithPatchesParams<TKey, TMap>,
1539+
function mergeCollectionWithPatches<TKey extends CollectionKeyBase>(
1540+
{collectionKey, collection, mergeReplaceNullPatches, isProcessingCollectionUpdate = false}: MergeCollectionWithPatchesParams<TKey>,
15401541
retryAttempt?: number,
15411542
): Promise<void> {
15421543
if (!isValidNonEmptyCollectionForMerge(collection)) {
@@ -1654,7 +1655,12 @@ function mergeCollectionWithPatches<TKey extends CollectionKeyBase, TMap>(
16541655

16551656
return Promise.all(promises)
16561657
.catch((error) =>
1657-
retryOperation(error, mergeCollectionWithPatches, {collectionKey, collection: resultCollection, mergeReplaceNullPatches, isProcessingCollectionUpdate}, retryAttempt),
1658+
retryOperation(
1659+
error,
1660+
mergeCollectionWithPatches,
1661+
{collectionKey, collection: resultCollection as OnyxMergeCollectionInput<TKey>, mergeReplaceNullPatches, isProcessingCollectionUpdate},
1662+
retryAttempt,
1663+
),
16581664
)
16591665
.then(() => {
16601666
sendActionToDevTools(METHOD.MERGE_COLLECTION, undefined, resultCollection);
@@ -1674,7 +1680,7 @@ function mergeCollectionWithPatches<TKey extends CollectionKeyBase, TMap>(
16741680
* @param params.collection Object collection keyed by individual collection member keys and values
16751681
* @param retryAttempt retry attempt
16761682
*/
1677-
function partialSetCollection<TKey extends CollectionKeyBase, TMap>({collectionKey, collection}: SetCollectionParams<TKey, TMap>, retryAttempt?: number): Promise<void> {
1683+
function partialSetCollection<TKey extends CollectionKeyBase>({collectionKey, collection}: SetCollectionParams<TKey>, retryAttempt?: number): Promise<void> {
16781684
let resultCollection: OnyxInputKeyValueMapping = collection;
16791685
let resultCollectionKeys = Object.keys(resultCollection);
16801686

lib/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
OnyxMultiSetInput,
1717
OnyxMergeInput,
1818
OnyxMergeCollectionInput,
19+
OnyxSetCollectionInput,
1920
} from './types';
2021
import type {FetchStatus, ResultMetadata, UseOnyxResult, UseOnyxOptions} from './useOnyx';
2122
import type {Connection} from './OnyxConnectionManager';
@@ -40,6 +41,7 @@ export type {
4041
OnyxMultiSetInput,
4142
OnyxMergeInput,
4243
OnyxMergeCollectionInput,
44+
OnyxSetCollectionInput,
4345
OnyxUpdate,
4446
OnyxValue,
4547
ResultMetadata,

lib/types.ts

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type {Merge} from 'type-fest';
2-
import type {BuiltIns} from 'type-fest/source/internal';
32
import type OnyxUtils from './OnyxUtils';
43
import type {OnyxMethod} from './OnyxUtils';
54
import type {FastMergeReplaceNullPatch} from './utils';
@@ -157,6 +156,10 @@ type OnyxValue<TKey extends OnyxKey> = string extends TKey ? unknown : TKey exte
157156
/** Utility type to extract `TOnyxValue` from `OnyxCollection<TOnyxValue>` */
158157
type ExtractOnyxCollectionValue<TOnyxCollection> = TOnyxCollection extends NonNullable<OnyxCollection<infer U>> ? U : never;
159158

159+
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
160+
161+
type BuiltIns = Primitive | void | Date | RegExp;
162+
160163
type NonTransformableTypes =
161164
| BuiltIns
162165
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -205,13 +208,7 @@ type NullishObjectDeep<ObjectType extends object> = {
205208
* Also, the `TMap` type is inferred automatically in `mergeCollection()` method and represents
206209
* the object of collection keys/values specified in the second parameter of the method.
207210
*/
208-
type Collection<TKey extends CollectionKeyBase, TValue, TMap = never> = {
209-
[MapK in keyof TMap]: MapK extends `${TKey}${string}`
210-
? MapK extends `${TKey}`
211-
? never // forbids empty id
212-
: TValue
213-
: never;
214-
};
211+
type Collection<TKey extends CollectionKeyBase, TValue> = Record<`${TKey}${string}`, TValue> & {[P in TKey]?: never};
215212

216213
/** Represents the base options used in `Onyx.connect()` method. */
217214
// NOTE: Any changes to this type like adding or removing options must be accounted in OnyxConnectionManager's `generateConnectionID()` method!
@@ -322,48 +319,58 @@ type OnyxMergeInput<TKey extends OnyxKey> = OnyxInput<TKey>;
322319
/**
323320
* This represents the value that can be passed to `Onyx.merge` and to `Onyx.update` with the method "MERGE"
324321
*/
325-
type OnyxMergeCollectionInput<TKey extends OnyxKey, TMap = object> = Collection<TKey, NonNullable<OnyxInput<TKey>>, TMap>;
322+
type OnyxMergeCollectionInput<TKey extends OnyxKey> = Collection<TKey, NonNullable<OnyxInput<TKey>>>;
326323

327-
type OnyxMethodMap = typeof OnyxUtils.METHOD;
324+
/**
325+
* This represents the value that can be passed to `Onyx.setCollection` and to `Onyx.update` with the method "SET_COLLECTION"
326+
*/
327+
type OnyxSetCollectionInput<TKey extends OnyxKey> = Collection<TKey, OnyxInput<TKey>>;
328328

329-
// Maps onyx methods to their corresponding value types
330-
type OnyxMethodValueMap = {
331-
[OnyxUtils.METHOD.SET]: {
332-
key: OnyxKey;
333-
value: OnyxSetInput<OnyxKey>;
334-
};
335-
[OnyxUtils.METHOD.MULTI_SET]: {
336-
key: OnyxKey;
337-
value: OnyxMultiSetInput;
338-
};
339-
[OnyxUtils.METHOD.MERGE]: {
340-
key: OnyxKey;
341-
value: OnyxMergeInput<OnyxKey>;
342-
};
343-
[OnyxUtils.METHOD.CLEAR]: {
344-
key: OnyxKey;
345-
value?: undefined;
346-
};
347-
[OnyxUtils.METHOD.MERGE_COLLECTION]: {
348-
key: CollectionKeyBase;
349-
value: OnyxMergeCollectionInput<CollectionKeyBase>;
350-
};
351-
[OnyxUtils.METHOD.SET_COLLECTION]: {
352-
key: CollectionKeyBase;
353-
value: OnyxMergeCollectionInput<CollectionKeyBase>;
354-
};
355-
};
329+
type OnyxMethodMap = typeof OnyxUtils.METHOD;
356330

357331
/**
358332
* OnyxUpdate type includes all onyx methods used in OnyxMethodValueMap.
359333
* If a new method is added to OnyxUtils.METHOD constant, it must be added to OnyxMethodValueMap type.
360334
* Otherwise it will show static type errors.
361335
*/
362-
type OnyxUpdate = {
363-
[Method in OnyxMethod]: {
364-
onyxMethod: Method;
365-
} & OnyxMethodValueMap[Method];
366-
}[OnyxMethod];
336+
type OnyxUpdate =
337+
// ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️
338+
| {
339+
[TKey in OnyxKey]:
340+
| {
341+
onyxMethod: typeof OnyxUtils.METHOD.SET;
342+
key: TKey;
343+
value: OnyxSetInput<TKey>;
344+
}
345+
| {
346+
onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET;
347+
key: TKey;
348+
value: OnyxMultiSetInput;
349+
}
350+
| {
351+
onyxMethod: typeof OnyxUtils.METHOD.MERGE;
352+
key: TKey;
353+
value: OnyxMergeInput<TKey>;
354+
}
355+
| {
356+
onyxMethod: typeof OnyxUtils.METHOD.CLEAR;
357+
key: TKey;
358+
value?: undefined;
359+
};
360+
}[OnyxKey]
361+
| {
362+
[TKey in CollectionKeyBase]:
363+
| {
364+
onyxMethod: typeof OnyxUtils.METHOD.MERGE_COLLECTION;
365+
key: TKey;
366+
value: OnyxMergeCollectionInput<TKey>;
367+
}
368+
| {
369+
onyxMethod: typeof OnyxUtils.METHOD.SET_COLLECTION;
370+
key: TKey;
371+
value: OnyxSetCollectionInput<TKey>;
372+
};
373+
}[CollectionKeyBase];
367374

368375
/**
369376
* Represents the options used in `Onyx.set()` method.
@@ -379,14 +386,14 @@ type SetParams<TKey extends OnyxKey> = {
379386
options?: SetOptions;
380387
};
381388

382-
type SetCollectionParams<TKey extends CollectionKeyBase, TMap> = {
389+
type SetCollectionParams<TKey extends CollectionKeyBase> = {
383390
collectionKey: TKey;
384-
collection: OnyxMergeCollectionInput<TKey, TMap>;
391+
collection: OnyxSetCollectionInput<TKey>;
385392
};
386393

387-
type MergeCollectionWithPatchesParams<TKey extends CollectionKeyBase, TMap> = {
394+
type MergeCollectionWithPatchesParams<TKey extends CollectionKeyBase> = {
388395
collectionKey: TKey;
389-
collection: OnyxMergeCollectionInput<TKey, TMap>;
396+
collection: OnyxMergeCollectionInput<TKey>;
390397
mergeReplaceNullPatches?: MultiMergeReplaceNullPatches;
391398
isProcessingCollectionUpdate?: boolean;
392399
};
@@ -499,6 +506,7 @@ export type {
499506
OnyxMultiSetInput,
500507
OnyxMergeInput,
501508
OnyxMergeCollectionInput,
509+
OnyxSetCollectionInput,
502510
OnyxMethod,
503511
OnyxMethodMap,
504512
OnyxUpdate,

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-onyx",
3-
"version": "3.0.10",
3+
"version": "3.0.11",
44
"author": "Expensify, Inc.",
55
"homepage": "https://expensify.com",
66
"description": "State management for React Native",
@@ -32,6 +32,7 @@
3232
"lint": "eslint .",
3333
"typecheck": "tsc --noEmit",
3434
"test": "jest",
35+
"test:types": "npm run build && tsc --noEmit --project tsconfig.test.json",
3536
"perf-test": "npx reassure",
3637
"build": "tsc -p tsconfig.build.json",
3738
"build:watch": "nodemon --watch lib --ext js,json,ts,tsx --exec \"npm run build && npm pack\"",

0 commit comments

Comments
 (0)