From d965defbc96d1e2515cac9c39d69809efb0e472a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 18 Nov 2025 08:47:56 +0100 Subject: [PATCH 1/8] Refactor OnyxUpdate type to support generics for improved performance --- lib/Onyx.ts | 4 +- lib/OnyxUtils.ts | 2 +- lib/types.ts | 79 ++++++++++++++------------ tests/perf-test/Onyx.perf-test.ts | 8 +-- tests/perf-test/OnyxUtils.perf-test.ts | 4 +- tests/types/OnyxUpdate.ts | 12 ++-- tests/unit/onyxTest.ts | 18 +++--- 7 files changed, 67 insertions(+), 60 deletions(-) diff --git a/lib/Onyx.ts b/lib/Onyx.ts index cac0ca1c3..876a5c44d 100644 --- a/lib/Onyx.ts +++ b/lib/Onyx.ts @@ -396,7 +396,7 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise { * @param data An array of objects with update expressions * @returns resolves when all operations are complete */ -function update(data: OnyxUpdate[]): Promise { +function update(data: Array>): Promise { // First, validate the Onyx object is in the format we expect data.forEach(({onyxMethod, key, value}) => { if (!Object.values(OnyxUtils.METHOD).includes(onyxMethod)) { @@ -453,7 +453,7 @@ function update(data: OnyxUpdate[]): Promise { collectionKeys.forEach((collectionKey) => enqueueMergeOperation(collectionKey, mergedCollection[collectionKey])); } }, - [OnyxUtils.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k, v as OnyxSetCollectionInput)), + [OnyxUtils.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k, v as OnyxSetCollectionInput)), [OnyxUtils.METHOD.MULTI_SET]: (k, v) => Object.entries(v as Partial).forEach(([entryKey, entryValue]) => enqueueSetOperation(entryKey, entryValue)), [OnyxUtils.METHOD.CLEAR]: () => { clearPromise = clear(); diff --git a/lib/OnyxUtils.ts b/lib/OnyxUtils.ts index c3d66c3f7..58168e02f 100644 --- a/lib/OnyxUtils.ts +++ b/lib/OnyxUtils.ts @@ -1209,7 +1209,7 @@ function unsubscribeFromKey(subscriptionID: number): void { delete callbackToStateMapping[subscriptionID]; } -function updateSnapshots(data: OnyxUpdate[], mergeFn: typeof Onyx.merge): Array<() => Promise> { +function updateSnapshots(data: Array>, mergeFn: typeof Onyx.merge): Array<() => Promise> { const snapshotCollectionKey = getSnapshotKey(); if (!snapshotCollectionKey) return []; diff --git a/lib/types.ts b/lib/types.ts index c802814c4..e802dab05 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -328,49 +328,56 @@ type OnyxSetCollectionInput = Collection = { // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ - | { - [TKey in OnyxKey]: - | { - onyxMethod: typeof OnyxUtils.METHOD.SET; - key: TKey; - value: OnyxSetInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET; - key: TKey; - value: OnyxMultiSetInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.MERGE; - key: TKey; - value: OnyxMergeInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.CLEAR; - key: TKey; - value?: undefined; - }; - }[OnyxKey] - | { - [TKey in CollectionKeyBase]: + [K in TKey]: + | { + onyxMethod: typeof OnyxUtils.METHOD.SET; + key: K; + value: OnyxSetInput; + } + | { + onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET; + key: K; + value: OnyxMultiSetInput; + } + | { + onyxMethod: typeof OnyxUtils.METHOD.MERGE; + key: K; + value: OnyxMergeInput; + } + | { + onyxMethod: typeof OnyxUtils.METHOD.CLEAR; + key: K; + value?: undefined; + }; +}[TKey]; + +type OnyxUpdateCollection = TKey extends CollectionKeyBase + ? // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ + { + [K in TKey]: | { onyxMethod: typeof OnyxUtils.METHOD.MERGE_COLLECTION; - key: TKey; - value: OnyxMergeCollectionInput; + key: K; + value: OnyxMergeCollectionInput; } | { onyxMethod: typeof OnyxUtils.METHOD.SET_COLLECTION; - key: TKey; - value: OnyxSetCollectionInput; + key: K; + value: OnyxSetCollectionInput; }; - }[CollectionKeyBase]; + }[TKey] + : never; + +/** + * OnyxUpdate type includes all onyx methods used in OnyxMethodValueMap. + * If a new method is added to OnyxUtils.METHOD constant, it must be added to OnyxMethodValueMap type. + * Otherwise it will show static type errors. + */ +type OnyxUpdate = + // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ + OnyxUpdateBase | OnyxUpdateCollection; /** * Represents the options used in `Onyx.set()` method. diff --git a/tests/perf-test/Onyx.perf-test.ts b/tests/perf-test/Onyx.perf-test.ts index 8a0c53650..31a135692 100644 --- a/tests/perf-test/Onyx.perf-test.ts +++ b/tests/perf-test/Onyx.perf-test.ts @@ -1,5 +1,5 @@ import {measureAsyncFunction} from 'reassure'; -import type {OnyxUpdate} from '../../lib'; +import type {OnyxKey, OnyxUpdate} from '../../lib'; import Onyx from '../../lib'; import createRandomReportAction, {getRandomReportActions} from '../utils/collections/reportActions'; import type GenericCollection from '../utils/GenericCollection'; @@ -115,13 +115,13 @@ describe('Onyx', () => { const sets = Object.entries(changedReportActions) .filter(([, v]) => Number(v.reportActionID) % 2 === 0) - .map(([k, v]): OnyxUpdate => ({key: k, onyxMethod: Onyx.METHOD.SET, value: v})); + .map(([k, v]): OnyxUpdate => ({key: k, onyxMethod: Onyx.METHOD.SET, value: v})); const merges = Object.entries(changedReportActions) .filter(([, v]) => Number(v.reportActionID) % 2 !== 0) - .map(([k, v]): OnyxUpdate => ({key: k, onyxMethod: Onyx.METHOD.MERGE, value: v})); + .map(([k, v]): OnyxUpdate => ({key: k, onyxMethod: Onyx.METHOD.MERGE, value: v})); - const updates = alternateLists(sets, merges) as OnyxUpdate[]; + const updates = alternateLists(sets, merges) as Array>; await measureAsyncFunction(() => Onyx.update(updates), { beforeEach: async () => { diff --git a/tests/perf-test/OnyxUtils.perf-test.ts b/tests/perf-test/OnyxUtils.perf-test.ts index ea8844a2a..26905822e 100644 --- a/tests/perf-test/OnyxUtils.perf-test.ts +++ b/tests/perf-test/OnyxUtils.perf-test.ts @@ -9,7 +9,7 @@ import OnyxUtils, {clearOnyxUtilsInternals} from '../../lib/OnyxUtils'; import type GenericCollection from '../utils/GenericCollection'; import type {OnyxUpdate} from '../../lib/Onyx'; import createDeferredTask from '../../lib/createDeferredTask'; -import type {OnyxInputKeyValueMapping, RetriableOnyxOperation} from '../../lib/types'; +import type {OnyxInputKeyValueMapping, OnyxKey, RetriableOnyxOperation} from '../../lib/types'; const ONYXKEYS = { TEST_KEY: 'test', @@ -806,7 +806,7 @@ describe('OnyxUtils', () => { describe('updateSnapshots', () => { test('one call with 100 updates', async () => { - const updates: OnyxUpdate[] = []; + const updates: Array> = []; for (let i = 0; i < 100; i++) { updates.push({ onyxMethod: OnyxUtils.METHOD.MERGE, diff --git a/tests/types/OnyxUpdate.ts b/tests/types/OnyxUpdate.ts index e1b8567ce..121e009c8 100644 --- a/tests/types/OnyxUpdate.ts +++ b/tests/types/OnyxUpdate.ts @@ -1,20 +1,20 @@ import type {OnyxUpdate} from '../../dist/types'; import ONYX_KEYS from './setup'; -const onyxUpdate: OnyxUpdate = { +const onyxUpdate: OnyxUpdate<'test'> = { onyxMethod: 'set', key: ONYX_KEYS.TEST_KEY, value: 'string', }; -const onyxUpdateError: OnyxUpdate = { +const onyxUpdateError: OnyxUpdate<'test'> = { onyxMethod: 'set', key: ONYX_KEYS.TEST_KEY, // @ts-expect-error TEST_KEY is a string, not a number value: 2, }; -const onyxUpdateCollection: OnyxUpdate = { +const onyxUpdateCollection: OnyxUpdate<'test_'> = { onyxMethod: 'mergecollection', key: ONYX_KEYS.COLLECTION.TEST_KEY, value: { @@ -28,7 +28,7 @@ const onyxUpdateCollection: OnyxUpdate = { }; // @ts-expect-error COLLECTION.TEST_KEY is an object, not a number -const onyxUpdateCollectionError: OnyxUpdate = { +const onyxUpdateCollectionError: OnyxUpdate<'test_'> = { onyxMethod: 'mergecollection', key: ONYX_KEYS.COLLECTION.TEST_KEY, value: { @@ -36,7 +36,7 @@ const onyxUpdateCollectionError: OnyxUpdate = { }, }; -const onyxUpdateCollectionError2: OnyxUpdate = { +const onyxUpdateCollectionError2: OnyxUpdate<'test_'> = { onyxMethod: 'mergecollection', key: ONYX_KEYS.COLLECTION.TEST_KEY, value: { @@ -48,7 +48,7 @@ const onyxUpdateCollectionError2: OnyxUpdate = { }; // @ts-expect-error COLLECTION.TEST_KEY is invalid key, it is missing the suffix -const onyxUpdateCollectionError3: OnyxUpdate = { +const onyxUpdateCollectionError3: OnyxUpdate<'test_'> = { onyxMethod: 'mergecollection', key: ONYX_KEYS.COLLECTION.TEST_KEY, value: { diff --git a/tests/unit/onyxTest.ts b/tests/unit/onyxTest.ts index 066f4513f..5f3e9afd7 100644 --- a/tests/unit/onyxTest.ts +++ b/tests/unit/onyxTest.ts @@ -5,7 +5,7 @@ import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; import OnyxUtils from '../../lib/OnyxUtils'; import type OnyxCache from '../../lib/OnyxCache'; import StorageMock from '../../lib/storage'; -import type {OnyxCollection, OnyxUpdate} from '../../lib/types'; +import type {OnyxCollection, OnyxKey, OnyxUpdate} from '../../lib/types'; import type {GenericDeepRecord} from '../types'; import type GenericCollection from '../utils/GenericCollection'; import type {Connection} from '../../lib/OnyxConnectionManager'; @@ -997,7 +997,7 @@ describe('Onyx', () => { }, }, }, - ] as unknown as OnyxUpdate[]), + ] as unknown as Array>), ) .then(() => { expect(valuesReceived).toEqual({ @@ -1029,7 +1029,7 @@ describe('Onyx', () => { }, ], }, - ] as unknown as OnyxUpdate[]); + ] as unknown as Array>); } catch (error) { if (error instanceof Error) { expect(error.message).toEqual('Invalid value provided in Onyx multiSet. Onyx multiSet value must be of type object.'); @@ -1825,7 +1825,7 @@ describe('Onyx', () => { }, }); - const queuedUpdates: OnyxUpdate[] = [ + const queuedUpdates: Array> = [ { key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`, onyxMethod: 'merge', @@ -1872,7 +1872,7 @@ describe('Onyx', () => { await Onyx.multiSet({[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`]: entry1}); const entry1ExpectedResult = lodashCloneDeep(entry1); - const queuedUpdates: OnyxUpdate[] = []; + const queuedUpdates: Array> = []; queuedUpdates.push({ key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`, @@ -1919,7 +1919,7 @@ describe('Onyx', () => { await Onyx.multiSet({[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`]: entry1}); const entry1ExpectedResult = lodashCloneDeep(entry1); - const queuedUpdates: OnyxUpdate[] = []; + const queuedUpdates: Array> = []; queuedUpdates.push({ key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`, @@ -1991,7 +1991,7 @@ describe('Onyx', () => { await Onyx.multiSet({[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`]: entry1}); const entry1ExpectedResult = lodashCloneDeep(entry1); - const queuedUpdates: OnyxUpdate[] = []; + const queuedUpdates: Array> = []; queuedUpdates.push({ key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`, @@ -2048,7 +2048,7 @@ describe('Onyx', () => { }); let entry1ExpectedResult = lodashCloneDeep(entry1) as GenericDeepRecord | undefined; - const queuedUpdates: OnyxUpdate[] = []; + const queuedUpdates: Array> = []; queuedUpdates.push({ key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`, @@ -2121,7 +2121,7 @@ describe('Onyx', () => { const entry1ExpectedResult = lodashCloneDeep(entry1); const entry2ExpectedResult = lodashCloneDeep(entry2); - const queuedUpdates: OnyxUpdate[] = []; + const queuedUpdates: Array> = []; queuedUpdates.push( { From 7e27273cfd45dc6c55cf8462d5f3ab41a3838e31 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 18 Nov 2025 14:48:57 +0100 Subject: [PATCH 2/8] Transform collection key base into collection key with id --- lib/types.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index e802dab05..37ef7c458 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -328,27 +328,29 @@ type OnyxSetCollectionInput = Collection = TKey extends CollectionKeyBase ? `${TKey}${string}` : TKey; + type OnyxUpdateBase = { // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ [K in TKey]: | { onyxMethod: typeof OnyxUtils.METHOD.SET; - key: K; + key: ExpandOnyxKeys; value: OnyxSetInput; } | { onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET; - key: K; + key: ExpandOnyxKeys; value: OnyxMultiSetInput; } | { onyxMethod: typeof OnyxUtils.METHOD.MERGE; - key: K; + key: ExpandOnyxKeys; value: OnyxMergeInput; } | { onyxMethod: typeof OnyxUtils.METHOD.CLEAR; - key: K; + key: ExpandOnyxKeys; value?: undefined; }; }[TKey]; From dd47c303490f61bb99171f5aa24df84f8ad4699b Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Nov 2025 16:53:07 +0100 Subject: [PATCH 3/8] Refactor setCollection method after review --- lib/Onyx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Onyx.ts b/lib/Onyx.ts index 876a5c44d..eb79d42f7 100644 --- a/lib/Onyx.ts +++ b/lib/Onyx.ts @@ -453,7 +453,7 @@ function update(data: Array>): Promise enqueueMergeOperation(collectionKey, mergedCollection[collectionKey])); } }, - [OnyxUtils.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k, v as OnyxSetCollectionInput)), + [OnyxUtils.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k as TKey, v as OnyxSetCollectionInput)), [OnyxUtils.METHOD.MULTI_SET]: (k, v) => Object.entries(v as Partial).forEach(([entryKey, entryValue]) => enqueueSetOperation(entryKey, entryValue)), [OnyxUtils.METHOD.CLEAR]: () => { clearPromise = clear(); From 875c7c3402e4f66d00e65f438c1854621f599af1 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Nov 2025 22:12:21 +0100 Subject: [PATCH 4/8] Fix how Onyx.update narrows down its generic --- lib/types.ts | 55 ++++++++++------------------------------------------ 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 37ef7c458..132b5239d 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -328,58 +328,23 @@ type OnyxSetCollectionInput = Collection = TKey extends CollectionKeyBase ? `${TKey}${string}` : TKey; - -type OnyxUpdateBase = { - // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ - [K in TKey]: - | { - onyxMethod: typeof OnyxUtils.METHOD.SET; - key: ExpandOnyxKeys; - value: OnyxSetInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET; - key: ExpandOnyxKeys; - value: OnyxMultiSetInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.MERGE; - key: ExpandOnyxKeys; - value: OnyxMergeInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.CLEAR; - key: ExpandOnyxKeys; - value?: undefined; - }; -}[TKey]; - -type OnyxUpdateCollection = TKey extends CollectionKeyBase - ? // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ - { - [K in TKey]: - | { - onyxMethod: typeof OnyxUtils.METHOD.MERGE_COLLECTION; - key: K; - value: OnyxMergeCollectionInput; - } - | { - onyxMethod: typeof OnyxUtils.METHOD.SET_COLLECTION; - key: K; - value: OnyxSetCollectionInput; - }; - }[TKey] - : never; +type ExpandOnyxKeys = TKey extends CollectionKeyBase ? NoInfer<`${TKey}${string}`> : TKey; /** * OnyxUpdate type includes all onyx methods used in OnyxMethodValueMap. * If a new method is added to OnyxUtils.METHOD constant, it must be added to OnyxMethodValueMap type. * Otherwise it will show static type errors. */ -type OnyxUpdate = +type OnyxUpdate = { // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ - OnyxUpdateBase | OnyxUpdateCollection; + [K in TKey]: + | {onyxMethod: typeof OnyxUtils.METHOD.SET; key: ExpandOnyxKeys; value: OnyxSetInput} + | {onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET; key: ExpandOnyxKeys; value: OnyxMultiSetInput} + | {onyxMethod: typeof OnyxUtils.METHOD.MERGE; key: ExpandOnyxKeys; value: OnyxMergeInput} + | {onyxMethod: typeof OnyxUtils.METHOD.CLEAR; key: ExpandOnyxKeys; value?: never} + | {onyxMethod: typeof OnyxUtils.METHOD.MERGE_COLLECTION; key: K; value: OnyxMergeCollectionInput} + | {onyxMethod: typeof OnyxUtils.METHOD.SET_COLLECTION; key: K; value: OnyxSetCollectionInput}; +}[TKey]; /** * Represents the options used in `Onyx.set()` method. From 64e13e84b64478c2bef8dc2bd54d5a4701efb1d1 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Nov 2025 22:12:37 +0100 Subject: [PATCH 5/8] Add multiple Onyx.update type tests --- tests/types/OnyxUpdate.ts | 74 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/types/OnyxUpdate.ts b/tests/types/OnyxUpdate.ts index 121e009c8..4ca0e6c17 100644 --- a/tests/types/OnyxUpdate.ts +++ b/tests/types/OnyxUpdate.ts @@ -1,3 +1,4 @@ +import Onyx from '../../dist/Onyx'; import type {OnyxUpdate} from '../../dist/types'; import ONYX_KEYS from './setup'; @@ -57,3 +58,76 @@ const onyxUpdateCollectionError3: OnyxUpdate<'test_'> = { }, }, }; + +Onyx.update([ + { + onyxMethod: 'mergecollection', + key: ONYX_KEYS.COLLECTION.TEST_KEY, + value: { + [`${ONYX_KEYS.COLLECTION.TEST_KEY}1`]: { + str: 'test1', + }, + [`${ONYX_KEYS.COLLECTION.TEST_KEY}2`]: { + str: 'test2', + }, + }, + }, + { + onyxMethod: 'setcollection', + key: ONYX_KEYS.COLLECTION.TEST_KEY, + value: { + [`${ONYX_KEYS.COLLECTION.TEST_KEY}1`]: { + str: 'test1', + }, + }, + }, + { + onyxMethod: 'set', + key: ONYX_KEYS.TEST_KEY, + value: 'string', + }, +]); + +Onyx.update([ + { + onyxMethod: 'clear', + key: ONYX_KEYS.TEST_KEY, + }, +]); + +Onyx.update([ + { + onyxMethod: 'merge', + key: ONYX_KEYS.COLLECTION.TEST_KEY, + value: { + str: 'test1', + }, + }, + { + onyxMethod: 'set', + key: ONYX_KEYS.TEST_KEY, + value: 'string', + }, +]); + +Onyx.update([ + { + onyxMethod: 'set', + key: ONYX_KEYS.TEST_KEY, + // @ts-expect-error TEST_KEY is a string, not a boolean + value: true, + }, +]); + +Onyx.update([ + // @ts-expect-error COLLECTION.TEST_KEY is invalid key, it is missing the suffix + { + onyxMethod: 'mergecollection', + key: ONYX_KEYS.COLLECTION.TEST_KEY, + value: { + [ONYX_KEYS.COLLECTION.TEST_KEY]: { + str: 'test1', + }, + }, + }, +]); From 8bae0565a6957b9db40bbd92af4a5c1907ae8325 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Nov 2025 22:46:37 +0100 Subject: [PATCH 6/8] Add OnyxUpdate type test for collection member --- tests/types/OnyxUpdate.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/types/OnyxUpdate.ts b/tests/types/OnyxUpdate.ts index 4ca0e6c17..5a19ddf63 100644 --- a/tests/types/OnyxUpdate.ts +++ b/tests/types/OnyxUpdate.ts @@ -8,6 +8,14 @@ const onyxUpdate: OnyxUpdate<'test'> = { value: 'string', }; +const onyxUpdateCollectionMember: OnyxUpdate = { + onyxMethod: 'set', + key: `${ONYX_KEYS.COLLECTION.TEST_KEY}1`, + value: { + str: 'test1', + }, +}; + const onyxUpdateError: OnyxUpdate<'test'> = { onyxMethod: 'set', key: ONYX_KEYS.TEST_KEY, From 1dd091dd6e43ba80f2516c01953057909abe213f Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 8 Dec 2025 16:15:24 +0100 Subject: [PATCH 7/8] Add generic default type to OnyxUpdate --- lib/types.ts | 4 ++-- tests/types/OnyxUpdate.ts | 10 +++++----- tests/unit/onyxTest.ts | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 132b5239d..6fae43cf3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -208,7 +208,7 @@ type NullishObjectDeep = { * Also, the `TMap` type is inferred automatically in `mergeCollection()` method and represents * the object of collection keys/values specified in the second parameter of the method. */ -type Collection = Record<`${TKey}${string}`, TValue> & {[P in TKey]?: never}; +type Collection = Record<`${TKey}${string}`, TValue>; /** Represents the base options used in `Onyx.connect()` method. */ // NOTE: Any changes to this type like adding or removing options must be accounted in OnyxConnectionManager's `generateConnectionID()` method! @@ -335,7 +335,7 @@ type ExpandOnyxKeys = TKey extends CollectionKeyBase ? NoI * If a new method is added to OnyxUtils.METHOD constant, it must be added to OnyxMethodValueMap type. * Otherwise it will show static type errors. */ -type OnyxUpdate = { +type OnyxUpdate = { // ⚠️ DO NOT CHANGE THIS TYPE, UNLESS YOU KNOW WHAT YOU ARE DOING. ⚠️ [K in TKey]: | {onyxMethod: typeof OnyxUtils.METHOD.SET; key: ExpandOnyxKeys; value: OnyxSetInput} diff --git a/tests/types/OnyxUpdate.ts b/tests/types/OnyxUpdate.ts index 5a19ddf63..c9ab44a50 100644 --- a/tests/types/OnyxUpdate.ts +++ b/tests/types/OnyxUpdate.ts @@ -1,5 +1,5 @@ import Onyx from '../../dist/Onyx'; -import type {OnyxUpdate} from '../../dist/types'; +import type {OnyxMergeCollectionInput, OnyxUpdate} from '../../dist/types'; import ONYX_KEYS from './setup'; const onyxUpdate: OnyxUpdate<'test'> = { @@ -56,12 +56,12 @@ const onyxUpdateCollectionError2: OnyxUpdate<'test_'> = { }, }; -// @ts-expect-error COLLECTION.TEST_KEY is invalid key, it is missing the suffix const onyxUpdateCollectionError3: OnyxUpdate<'test_'> = { onyxMethod: 'mergecollection', key: ONYX_KEYS.COLLECTION.TEST_KEY, value: { - [ONYX_KEYS.COLLECTION.TEST_KEY]: { + // @ts-expect-error nonExistingKey is not a valid key + ['nonExistingKey']: { str: 'test2', }, }, @@ -128,12 +128,12 @@ Onyx.update([ ]); Onyx.update([ - // @ts-expect-error COLLECTION.TEST_KEY is invalid key, it is missing the suffix { onyxMethod: 'mergecollection', key: ONYX_KEYS.COLLECTION.TEST_KEY, value: { - [ONYX_KEYS.COLLECTION.TEST_KEY]: { + // @ts-expect-error nonExistingKey is not a valid key + ['nonExistingKey']: { str: 'test1', }, }, diff --git a/tests/unit/onyxTest.ts b/tests/unit/onyxTest.ts index 5f3e9afd7..ecd73cfb7 100644 --- a/tests/unit/onyxTest.ts +++ b/tests/unit/onyxTest.ts @@ -2663,7 +2663,6 @@ describe('Onyx', () => { } as GenericCollection); await Onyx.setCollection(ONYX_KEYS.COLLECTION.ROUTES, { - // @ts-expect-error invalidRoute is not a valid key [invalidRoute]: {name: 'Invalid Route'}, }); From 2566e7b2b195ef42346fab1f3a0bd8c3bb38f567 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 8 Dec 2025 16:18:58 +0100 Subject: [PATCH 8/8] Update mergeCollection tests to include new invalid key scenarios --- tests/types/mergeCollection.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/types/mergeCollection.ts b/tests/types/mergeCollection.ts index 5d07fd217..6d004bf54 100644 --- a/tests/types/mergeCollection.ts +++ b/tests/types/mergeCollection.ts @@ -14,13 +14,16 @@ Onyx.mergeCollection(ONYX_KEYS.COLLECTION.TEST_KEY, { }); Onyx.mergeCollection(ONYX_KEYS.COLLECTION.TEST_KEY, { - // @ts-expect-error COLLECTION.TEST_KEY is invalid key, it is missing the suffix - test_: { - str: 'test3', - }, test_2: { str: 'test4', }, // @ts-expect-error COLLECTION.TEST_KEY is object, not a number test_3: 2, }); + +Onyx.mergeCollection(ONYX_KEYS.COLLECTION.TEST_KEY, { + // @ts-expect-error invalidKey is not a valid key + invalidKey: { + str: 'test3', + }, +});