Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/eslint/eslint.seatbelt.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@
"../../src/libs/Clipboard/index.ts" "@typescript-eslint/no-deprecated/document.execCommand" 1
"../../src/libs/Clipboard/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/libs/Clipboard/index.ts" "no-restricted-syntax" 1
"../../src/libs/cloneMutable.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/libs/ComposerFocusManager.ts" "@typescript-eslint/no-deprecated/TextInput.State.currentlyFocusedField" 1
"../../src/libs/ComposerFocusManager.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/libs/ComposerUtils/index.ts" "no-restricted-syntax" 1
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions patches/react-native-onyx/details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# `react-native-onyx` patches

### [react-native-onyx+3.0.110+001+readonly-types.patch](react-native-onyx+3.0.110+001+readonly-types.patch)

- Reason:

```
Proof of concept, not for merge. Makes the Onyx cache immutable at the type level, in the two places that
matter:

1. `Onyx.get()` returns `Promise<ReadonlyDeep<OnyxValue<TKey>>>`, so the object it hands back (which IS the
cached object, not a copy) cannot be mutated without the compiler objecting. This turns "the result of
Onyx.get() MUST NOT be mutated" from a convention reviewers have to remember into a rule tsc enforces.
2. Every write input (`OnyxInput`, which funnels into set/merge/multiSet/mergeCollection/setCollection/update)
is typed `ReadonlyDeep`, so a value read out of the cache can be passed straight back to a writer without a
copy. Without this half, every write path that echoes a read value needs a hand-rolled deep copy.

Both are widenings on the input side: nothing that passes a value in can break, and Onyx does not mutate write
inputs at runtime. See https://github.com/Expensify/App/issues/71206 for the measurements.
```

- Upstream PR/issue: https://github.com/Expensify/App/issues/71206
- E/App issue: https://github.com/Expensify/App/issues/71206
- PR introducing patch: experiment branch, no PR
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
diff --git a/node_modules/react-native-onyx/dist/Onyx.d.ts b/node_modules/react-native-onyx/dist/Onyx.d.ts
index b9848a6..c4045b1 100644
--- a/node_modules/react-native-onyx/dist/Onyx.d.ts
+++ b/node_modules/react-native-onyx/dist/Onyx.d.ts
@@ -1,4 +1,5 @@
import * as Logger from './Logger';
+import type { ReadonlyDeep } from 'type-fest';
import type { CollectionKeyBase, ConnectOptions, InitOptions, OnyxKey, OnyxMergeCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetCollectionInput, OnyxSetInput, OnyxUpdate, OnyxValue, SetOptions } from './types';
import type { Connection } from './OnyxConnectionManager';
/** Initialize the store with actions and listening for storage events */
@@ -170,7 +171,7 @@ declare function setCollection<TKey extends CollectionKeyBase>(collectionKey: TK
* @param key ONYXKEY to read, either a collection key or a single key
* @returns The current value, or `undefined` if the key has none.
*/
-declare function get<TKey extends OnyxKey>(key: TKey): Promise<OnyxValue<TKey>>;
+declare function get<TKey extends OnyxKey>(key: TKey): Promise<ReadonlyDeep<OnyxValue<TKey>>>;
declare const Onyx: {
METHOD: {
readonly SET: "set";
diff --git a/node_modules/react-native-onyx/dist/types.d.ts b/node_modules/react-native-onyx/dist/types.d.ts
index cb91605..f974c46 100644
--- a/node_modules/react-native-onyx/dist/types.d.ts
+++ b/node_modules/react-native-onyx/dist/types.d.ts
@@ -1,4 +1,4 @@
-import type { Merge } from 'type-fest';
+import type { Merge, ReadonlyDeep } from 'type-fest';
import type OnyxUtils from './OnyxUtils';
import type { OnyxMethod } from './OnyxUtils';
import type { FastMergeReplaceNullPatch } from './utils';
@@ -219,7 +219,7 @@ type OnyxCollectionInputValue<TOnyxValue> = OnyxInputValue<Record<string, TOnyxV
* Setting a key to `null` will remove the key from the store.
* `undefined` is not allowed for setting values, because it will have no effect on the data.
*/
-type OnyxInput<TKey extends OnyxKey> = OnyxInputValue<NullishDeep<KeyValueMapping[TKey]>>;
+type OnyxInput<TKey extends OnyxKey> = ReadonlyDeep<OnyxInputValue<NullishDeep<KeyValueMapping[TKey]>>>;
/**
* Represents a mapping object where each `OnyxKey` maps to either a value of its corresponding type in `KeyValueMapping` or `null`.
*
Loading
Loading