react-native-onyx 1.0.59 → 1.0.60

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,13 @@
1
+ declare type LogData = {
2
+ message: string;
3
+ level: 'alert' | 'info';
4
+ };
5
+
6
+ /**
7
+ * Register the logging callback
8
+ *
9
+ * @param callback
10
+ */
11
+ declare function registerLogger(callback: (data: LogData) => void): void;
12
+
13
+ export {registerLogger};
package/lib/Onyx.d.ts ADDED
@@ -0,0 +1,326 @@
1
+ import {Component} from 'react';
2
+ import {PartialDeep} from 'type-fest';
3
+ import * as Logger from './Logger';
4
+ import {
5
+ CollectionKey,
6
+ CollectionKeyBase,
7
+ DeepRecord,
8
+ KeyValueMapping,
9
+ OnyxCollection,
10
+ OnyxEntry,
11
+ OnyxKey,
12
+ } from './types';
13
+
14
+ /**
15
+ * Represents a mapping object where each `OnyxKey` maps to either a value of its corresponding type in `KeyValueMapping` or `null`.
16
+ *
17
+ * It's very similar to `KeyValueMapping` but this type accepts using `null` as well.
18
+ */
19
+ type NullableKeyValueMapping = {
20
+ [TKey in OnyxKey]: OnyxEntry<KeyValueMapping[TKey]>;
21
+ };
22
+
23
+ /**
24
+ * Represents the base options used in `Onyx.connect()` method.
25
+ */
26
+ type BaseConnectOptions = {
27
+ statePropertyName?: string;
28
+ withOnyxInstance?: Component;
29
+ initWithStoredValues?: boolean;
30
+ };
31
+
32
+ /**
33
+ * Represents the options used in `Onyx.connect()` method.
34
+ * The type is built from `BaseConnectOptions` and extended to handle key/callback related options.
35
+ * It includes two different forms, depending on whether we are waiting for a collection callback or not.
36
+ *
37
+ * If `waitForCollectionCallback` is `true`, it expects `key` to be a Onyx collection key and `callback` will be triggered with the whole collection
38
+ * and will pass `value` as an `OnyxCollection`.
39
+ *
40
+ *
41
+ * If `waitForCollectionCallback` is `false` or not specified, the `key` can be any Onyx key and `callback` will be triggered with updates of each collection item
42
+ * and will pass `value` as an `OnyxEntry`.
43
+ */
44
+ type ConnectOptions<TKey extends OnyxKey> = BaseConnectOptions &
45
+ (
46
+ | {
47
+ key: TKey extends CollectionKey ? TKey : never;
48
+ callback?: (value: OnyxCollection<KeyValueMapping[TKey]>, key?: TKey) => void;
49
+ waitForCollectionCallback: true;
50
+ }
51
+ | {
52
+ key: TKey;
53
+ callback?: (value: OnyxEntry<KeyValueMapping[TKey]>, key?: TKey) => void;
54
+ waitForCollectionCallback?: false;
55
+ }
56
+ );
57
+
58
+ /**
59
+ * Represents a mapping between Onyx collection keys and their respective values.
60
+ *
61
+ * It helps to enforce that a Onyx collection key should not be without suffix (e.g. should always be of the form `${TKey}${string}`),
62
+ * and to map each Onyx collection key with suffix to a value of type `TValue`.
63
+ *
64
+ * Also, the `TMap` type is inferred automatically in `mergeCollection()` method and represents
65
+ * the object of collection keys/values specified in the second parameter of the method.
66
+ */
67
+ type Collection<TKey extends CollectionKeyBase, TMap, TValue> = {
68
+ [MapK in keyof TMap]: MapK extends `${TKey}${string}`
69
+ ? MapK extends `${TKey}`
70
+ ? never // forbids empty id
71
+ : TValue
72
+ : never;
73
+ };
74
+
75
+ /**
76
+ * Represents different kinds of updates that can be passed to `Onyx.update()` method. It is a discriminated union of
77
+ * different update methods (`SET`, `MERGE`, `MERGE_COLLECTION`), each with their own key and value structure.
78
+ */
79
+ type OnyxUpdate =
80
+ | {
81
+ [TKey in OnyxKey]:
82
+ | {
83
+ onyxMethod: typeof METHOD.SET;
84
+ key: TKey;
85
+ value: OnyxEntry<KeyValueMapping[TKey]>;
86
+ }
87
+ | {
88
+ onyxMethod: typeof METHOD.MERGE;
89
+ key: TKey;
90
+ value: PartialDeep<KeyValueMapping[TKey]>;
91
+ };
92
+ }[OnyxKey]
93
+ | {
94
+ [TKey in CollectionKeyBase]: {
95
+ onyxMethod: typeof METHOD.MERGE_COLLECTION;
96
+ key: TKey;
97
+ value: Record<`${TKey}${string}`, PartialDeep<KeyValueMapping[TKey]>>;
98
+ };
99
+ }[CollectionKeyBase];
100
+
101
+ /**
102
+ * Represents the options used in `Onyx.init()` method.
103
+ */
104
+ type InitOptions = {
105
+ keys?: DeepRecord<string, OnyxKey>;
106
+ initialKeyStates?: Partial<NullableKeyValueMapping>;
107
+ safeEvictionKeys?: OnyxKey[];
108
+ maxCachedKeysCount?: number;
109
+ captureMetrics?: boolean;
110
+ shouldSyncMultipleInstances?: boolean;
111
+ debugSetState?: boolean;
112
+ };
113
+
114
+ declare const METHOD: {
115
+ readonly SET: 'set';
116
+ readonly MERGE: 'merge';
117
+ readonly MERGE_COLLECTION: 'mergecollection';
118
+ readonly CLEAR: 'clear';
119
+ };
120
+
121
+ /**
122
+ * Returns current key names stored in persisted storage
123
+ */
124
+ declare function getAllKeys(): Promise<Array<OnyxKey>>;
125
+
126
+ /**
127
+ * Checks to see if this key has been flagged as
128
+ * safe for removal.
129
+ */
130
+ declare function isSafeEvictionKey(testKey: OnyxKey): boolean;
131
+
132
+ /**
133
+ * Removes a key previously added to this list
134
+ * which will enable it to be deleted again.
135
+ */
136
+ declare function removeFromEvictionBlockList(key: OnyxKey, connectionID: number): void;
137
+
138
+ /**
139
+ * Keys added to this list can never be deleted.
140
+ */
141
+ declare function addToEvictionBlockList(key: OnyxKey, connectionID: number): void;
142
+
143
+ /**
144
+ * Subscribes a react component's state directly to a store key
145
+ *
146
+ * @example
147
+ * const connectionID = Onyx.connect({
148
+ * key: ONYXKEYS.SESSION,
149
+ * callback: onSessionChange,
150
+ * });
151
+ *
152
+ * @param mapping the mapping information to connect Onyx to the components state
153
+ * @param mapping.key ONYXKEY to subscribe to
154
+ * @param [mapping.statePropertyName] the name of the property in the state to connect the data to
155
+ * @param [mapping.withOnyxInstance] whose setState() method will be called with any changed data
156
+ * This is used by React components to connect to Onyx
157
+ * @param [mapping.callback] a method that will be called with changed data
158
+ * This is used by any non-React code to connect to Onyx
159
+ * @param [mapping.initWithStoredValues] If set to false, then no data will be prefilled into the
160
+ * component
161
+ * @param [mapping.waitForCollectionCallback] If set to true, it will return the entire collection to the callback as a single object
162
+ * @returns an ID to use when calling disconnect
163
+ */
164
+ declare function connect<TKey extends OnyxKey>(mapping: ConnectOptions<TKey>): number;
165
+
166
+ /**
167
+ * Remove the listener for a react component
168
+ * @example
169
+ * Onyx.disconnect(connectionID);
170
+ *
171
+ * @param connectionID unique id returned by call to Onyx.connect()
172
+ */
173
+ declare function disconnect(connectionID: number, keyToRemoveFromEvictionBlocklist?: OnyxKey): void;
174
+
175
+ /**
176
+ * Write a value to our store with the given key
177
+ *
178
+ * @param key ONYXKEY to set
179
+ * @param value value to store
180
+ */
181
+ declare function set<TKey extends OnyxKey>(key: TKey, value: OnyxEntry<KeyValueMapping[TKey]>): Promise<void>;
182
+
183
+ /**
184
+ * Sets multiple keys and values
185
+ *
186
+ * @example Onyx.multiSet({'key1': 'a', 'key2': 'b'});
187
+ *
188
+ * @param data object keyed by ONYXKEYS and the values to set
189
+ */
190
+ declare function multiSet(data: Partial<NullableKeyValueMapping>): Promise<void>;
191
+
192
+ /**
193
+ * Merge a new value into an existing value at a key.
194
+ *
195
+ * The types of values that can be merged are `Object` and `Array`. To set another type of value use `Onyx.set()`. Merge
196
+ * behavior uses lodash/merge under the hood for `Object` and simple concatenation for `Array`. However, it's important
197
+ * to note that if you have an array value property on an `Object` that the default behavior of lodash/merge is not to
198
+ * concatenate. See here: https://github.com/lodash/lodash/issues/2872
199
+ *
200
+ * Calls to `Onyx.merge()` are batched so that any calls performed in a single tick will stack in a queue and get
201
+ * applied in the order they were called. Note: `Onyx.set()` calls do not work this way so use caution when mixing
202
+ * `Onyx.merge()` and `Onyx.set()`.
203
+ *
204
+ * @example
205
+ * Onyx.merge(ONYXKEYS.EMPLOYEE_LIST, ['Joe']); // -> ['Joe']
206
+ * Onyx.merge(ONYXKEYS.EMPLOYEE_LIST, ['Jack']); // -> ['Joe', 'Jack']
207
+ * Onyx.merge(ONYXKEYS.POLICY, {id: 1}); // -> {id: 1}
208
+ * Onyx.merge(ONYXKEYS.POLICY, {name: 'My Workspace'}); // -> {id: 1, name: 'My Workspace'}
209
+ *
210
+ * @param key ONYXKEYS key
211
+ * @param value Object or Array value to merge
212
+ */
213
+ declare function merge<TKey extends OnyxKey>(key: TKey, value: PartialDeep<KeyValueMapping[TKey]>): Promise<void>;
214
+
215
+ /**
216
+ * Clear out all the data in the store
217
+ *
218
+ * Note that calling Onyx.clear() and then Onyx.set() on a key with a default
219
+ * key state may store an unexpected value in Storage.
220
+ *
221
+ * E.g.
222
+ * Onyx.clear();
223
+ * Onyx.set(ONYXKEYS.DEFAULT_KEY, 'default');
224
+ * Storage.getItem(ONYXKEYS.DEFAULT_KEY)
225
+ * .then((storedValue) => console.log(storedValue));
226
+ * null is logged instead of the expected 'default'
227
+ *
228
+ * Onyx.set() might call Storage.setItem() before Onyx.clear() calls
229
+ * Storage.setItem(). Use Onyx.merge() instead if possible. Onyx.merge() calls
230
+ * Onyx.get(key) before calling Storage.setItem() via Onyx.set().
231
+ * Storage.setItem() from Onyx.clear() will have already finished and the merged
232
+ * value will be saved to storage after the default value.
233
+ *
234
+ * @param keysToPreserve is a list of ONYXKEYS that should not be cleared with the rest of the data
235
+ */
236
+ declare function clear(keysToPreserve?: OnyxKey[]): Promise<void>;
237
+
238
+ /**
239
+ * Merges a collection based on their keys
240
+ *
241
+ * Note that both `TKey` and `TMap` types are inferred automatically, `TKey` being the
242
+ * collection key specified in the first parameter and `TMap` being the object of
243
+ * collection keys/values specified in the second parameter.
244
+ *
245
+ * @example
246
+ *
247
+ * Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, {
248
+ * [`${ONYXKEYS.COLLECTION.REPORT}1`]: report1,
249
+ * [`${ONYXKEYS.COLLECTION.REPORT}2`]: report2,
250
+ * });
251
+ *
252
+ * @param collectionKey e.g. `ONYXKEYS.COLLECTION.REPORT`
253
+ * @param collection Object collection keyed by individual collection member keys and values
254
+ */
255
+ declare function mergeCollection<TKey extends CollectionKeyBase, TMap>(
256
+ collectionKey: TKey,
257
+ collection: Collection<TKey, TMap, PartialDeep<KeyValueMapping[TKey]>>,
258
+ ): Promise<void>;
259
+
260
+ /**
261
+ * Insert API responses and lifecycle data into Onyx
262
+ *
263
+ * @param data An array of update objects
264
+ * @returns resolves when all operations are complete
265
+ */
266
+ declare function update(data: OnyxUpdate[]): Promise<void>;
267
+
268
+ /**
269
+ * Initialize the store with actions and listening for storage events
270
+ *
271
+ * @param [options={}] config object
272
+ * @param [options.keys={}] `ONYXKEYS` constants object
273
+ * @param [options.initialKeyStates={}] initial data to set when `init()` and `clear()` is called
274
+ * @param [options.safeEvictionKeys=[]] This is an array of keys
275
+ * (individual or collection patterns) that when provided to Onyx are flagged
276
+ * as "safe" for removal. Any components subscribing to these keys must also
277
+ * implement a canEvict option. See the README for more info.
278
+ * @param [options.maxCachedKeysCount=55] Sets how many recent keys should we try to keep in cache
279
+ * Setting this to 0 would practically mean no cache
280
+ * We try to free cache when we connect to a safe eviction key
281
+ * @param [options.captureMetrics] Enables Onyx benchmarking and exposes the get/print/reset functions
282
+ * @param [options.shouldSyncMultipleInstances] Auto synchronize storage events between multiple instances
283
+ * of Onyx running in different tabs/windows. Defaults to true for platforms that support local storage (web/desktop)
284
+ * @param [options.debugSetState] Enables debugging setState() calls to connected components.
285
+ * @example
286
+ * Onyx.init({
287
+ * keys: ONYXKEYS,
288
+ * initialKeyStates: {
289
+ * [ONYXKEYS.SESSION]: {loading: false},
290
+ * },
291
+ * });
292
+ */
293
+ declare function init(config?: InitOptions): void;
294
+
295
+ /**
296
+ * @private
297
+ */
298
+ declare function hasPendingMergeForKey(key: OnyxKey): boolean;
299
+
300
+ /**
301
+ * When set these keys will not be persisted to storage
302
+ */
303
+ declare function setMemoryOnlyKeys(keyList: OnyxKey[]): void;
304
+
305
+ declare const Onyx: {
306
+ connect: typeof connect;
307
+ disconnect: typeof disconnect;
308
+ set: typeof set;
309
+ multiSet: typeof multiSet;
310
+ merge: typeof merge;
311
+ mergeCollection: typeof mergeCollection;
312
+ hasPendingMergeForKey: typeof hasPendingMergeForKey;
313
+ update: typeof update;
314
+ clear: typeof clear;
315
+ getAllKeys: typeof getAllKeys;
316
+ init: typeof init;
317
+ registerLogger: typeof Logger.registerLogger;
318
+ addToEvictionBlockList: typeof addToEvictionBlockList;
319
+ removeFromEvictionBlockList: typeof removeFromEvictionBlockList;
320
+ isSafeEvictionKey: typeof isSafeEvictionKey;
321
+ METHOD: typeof METHOD;
322
+ setMemoryOnlyKeys: typeof setMemoryOnlyKeys;
323
+ };
324
+
325
+ export default Onyx;
326
+ export {OnyxUpdate};
package/lib/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import Onyx, {OnyxUpdate} from './Onyx';
2
+ import {CustomTypeOptions, OnyxCollection, OnyxEntry} from './types';
3
+ import withOnyx from './withOnyx';
4
+
5
+ export default Onyx;
6
+ export {CustomTypeOptions, OnyxCollection, OnyxEntry, OnyxUpdate, withOnyx};
package/lib/types.d.ts ADDED
@@ -0,0 +1,196 @@
1
+ import {IsEqual, Merge} from 'type-fest';
2
+
3
+ /**
4
+ * Represents a deeply nested record. It maps keys to values,
5
+ * and those values can either be of type `TValue` or further nested `DeepRecord` instances.
6
+ */
7
+ type DeepRecord<TKey extends string | number | symbol, TValue> = {[key: string]: TValue | DeepRecord<TKey, TValue>};
8
+
9
+ /**
10
+ * Represents type options to configure all Onyx methods.
11
+ * It's a combination of predefined options with user-provided options (CustomTypeOptions).
12
+ *
13
+ * The options are:
14
+ * - `keys`: Represents a string union of all Onyx normal keys.
15
+ * - `collectionKeys`: Represents a string union of all Onyx collection keys.
16
+ * - `values`: Represents a Record where each key is an Onyx key and each value is its corresponding Onyx value type.
17
+ *
18
+ * The user-defined options (CustomTypeOptions) are merged into these predefined options.
19
+ * In case of conflicting properties, the ones from CustomTypeOptions are prioritized.
20
+ */
21
+ type TypeOptions = Merge<
22
+ {
23
+ keys: string;
24
+ collectionKeys: string;
25
+ values: Record<string, unknown>;
26
+ },
27
+ CustomTypeOptions
28
+ >;
29
+
30
+ /**
31
+ * Represents the user-defined options to configure all Onyx methods.
32
+ *
33
+ * The developer can configure Onyx methods by augmenting this library and overriding CustomTypeOptions.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // ONYXKEYS.ts
38
+ * import {ValueOf} from 'type-fest';
39
+ * import { Account, Report } from './types';
40
+ *
41
+ * const ONYXKEYS = {
42
+ * ACCOUNT: 'account',
43
+ * IS_SIDEBAR_LOADED: 'isSidebarLoaded',
44
+ *
45
+ * // Collection Keys
46
+ * COLLECTION: {
47
+ * REPORT: 'report_',
48
+ * },
49
+ * } as const;
50
+ *
51
+ * type OnyxKeysMap = typeof ONYXKEYS;
52
+ * type OnyxCollectionKey = ValueOf<OnyxKeysMap['COLLECTION']>;
53
+ * type OnyxKey = DeepValueOf<Omit<OnyxKeysMap, 'COLLECTION'>>;
54
+ *
55
+ * type OnyxValues = {
56
+ * [ONYXKEYS.ACCOUNT]: Account;
57
+ * [ONYXKEYS.IS_SIDEBAR_LOADED]: boolean;
58
+ * [ONYXKEYS.COLLECTION.REPORT]: Report;
59
+ * };
60
+ *
61
+ * export default ONYXKEYS;
62
+ * export type {OnyxKey, OnyxCollectionKey, OnyxValues};
63
+ *
64
+ * // global.d.ts
65
+ * import {OnyxKey, OnyxCollectionKey, OnyxValues} from './ONYXKEYS';
66
+ *
67
+ * declare module 'react-native-onyx' {
68
+ * interface CustomTypeOptions {
69
+ * keys: OnyxKey;
70
+ * collectionKeys: OnyxCollectionKey;
71
+ * values: OnyxValues;
72
+ * }
73
+ * }
74
+ * ```
75
+ */
76
+ interface CustomTypeOptions {}
77
+
78
+ /**
79
+ * Represents a string union of all Onyx normal keys.
80
+ */
81
+ type Key = TypeOptions['keys'];
82
+
83
+ /**
84
+ * Represents a string union of all Onyx collection keys.
85
+ */
86
+ type CollectionKeyBase = TypeOptions['collectionKeys'];
87
+
88
+ /**
89
+ * Represents a literal string union of all Onyx collection keys.
90
+ * It allows appending a string after each collection key e.g. `report_some-id`.
91
+ */
92
+ type CollectionKey = `${CollectionKeyBase}${string}`;
93
+
94
+ /**
95
+ * Represents a string union of all Onyx normal and collection keys.
96
+ */
97
+ type OnyxKey = Key | CollectionKey;
98
+
99
+ /**
100
+ * Represents a mapping of Onyx keys to values, where keys are either normal or collection Onyx keys
101
+ * and values are the corresponding values in Onyx's state.
102
+ *
103
+ * For collection keys, `KeyValueMapping` allows any string to be appended
104
+ * to the key (e.g., 'report_some-id', 'download_some-id').
105
+ *
106
+ * The mapping is derived from the `values` property of the `TypeOptions` type.
107
+ */
108
+ type KeyValueMapping = {
109
+ [TKey in keyof TypeOptions['values'] as TKey extends CollectionKeyBase
110
+ ? `${TKey}${string}`
111
+ : TKey]: TypeOptions['values'][TKey];
112
+ };
113
+
114
+ /**
115
+ * Represents a selector function type which operates based on the provided `TKey` and `ReturnType`.
116
+ *
117
+ * A `Selector` is a function that accepts a value and returns a processed value.
118
+ * This type accepts two type parameters: `TKey` and `TReturnType`.
119
+ *
120
+ * The type `TKey` extends `OnyxKey` and it is the key used to access a value in `KeyValueMapping`.
121
+ * `TReturnType` is the type of the returned value from the selector function.
122
+ */
123
+ type Selector<TKey extends OnyxKey, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>) => TReturnType;
124
+
125
+ /**
126
+ * Represents a single Onyx entry, that can be either `TOnyxValue` or `null` if it doesn't exist.
127
+ *
128
+ * It can be used to specify data retrieved from Onyx e.g. `withOnyx` HOC mappings.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * import Onyx, {OnyxEntry, withOnyx} from 'react-native-onyx';
133
+ *
134
+ * type OnyxProps = {
135
+ * userAccount: OnyxEntry<Account>;
136
+ * };
137
+ *
138
+ * type Props = OnyxProps & {
139
+ * prop1: string;
140
+ * };
141
+ *
142
+ * function Component({prop1, userAccount}: Props) {
143
+ * // ...
144
+ * }
145
+ *
146
+ * export default withOnyx<Props, OnyxProps>({
147
+ * userAccount: {
148
+ * key: ONYXKEYS.ACCOUNT,
149
+ * },
150
+ * })(Component);
151
+ * ```
152
+ */
153
+ type OnyxEntry<TOnyxValue> = TOnyxValue | null;
154
+
155
+ /**
156
+ * Represents an Onyx collection of entries, that can be either a record of `TOnyxValue`s or `null` if it is empty or doesn't exist.
157
+ *
158
+ * It can be used to specify collection data retrieved from Onyx e.g. `withOnyx` HOC mappings.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * import Onyx, {OnyxCollection, withOnyx} from 'react-native-onyx';
163
+ *
164
+ * type OnyxProps = {
165
+ * reports: OnyxCollection<Report>;
166
+ * };
167
+ *
168
+ * type Props = OnyxProps & {
169
+ * prop1: string;
170
+ * };
171
+ *
172
+ * function Component({prop1, reports}: Props) {
173
+ * // ...
174
+ * }
175
+ *
176
+ * export default withOnyx<Props, OnyxProps>({
177
+ * reports: {
178
+ * key: ONYXKEYS.COLLECTION.REPORT,
179
+ * },
180
+ * })(Component);
181
+ * ```
182
+ */
183
+ type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue | null>>;
184
+
185
+ export {
186
+ CollectionKey,
187
+ CollectionKeyBase,
188
+ CustomTypeOptions,
189
+ DeepRecord,
190
+ Key,
191
+ KeyValueMapping,
192
+ OnyxCollection,
193
+ OnyxEntry,
194
+ OnyxKey,
195
+ Selector,
196
+ };
@@ -0,0 +1,153 @@
1
+ import {IsEqual} from 'type-fest';
2
+ import {CollectionKeyBase, KeyValueMapping, OnyxCollection, OnyxEntry, OnyxKey, Selector} from './types';
3
+
4
+ /**
5
+ * Represents the base mapping options between an Onyx key and the component's prop.
6
+ */
7
+ type BaseMapping<TComponentProps, TOnyxProps> = {
8
+ canEvict?: boolean | ((props: Omit<TComponentProps, keyof TOnyxProps>) => boolean);
9
+ initWithStoredValues?: boolean;
10
+ };
11
+
12
+ /**
13
+ * Represents the string / function `key` mapping option between an Onyx key and the component's prop.
14
+ *
15
+ * If `key` is `string`, the type of the Onyx value that is associated with `key` must match with the type of the component's prop,
16
+ * otherwise an error will be thrown.
17
+ *
18
+ * If `key` is `function`, the return type of `key` function must be a valid Onyx key and the type of the Onyx value associated
19
+ * with `key` must match with the type of the component's prop, otherwise an error will be thrown.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // Onyx prop with `string` key
24
+ * onyxProp: {
25
+ * key: ONYXKEYS.ACCOUNT,
26
+ * },
27
+ *
28
+ * // Onyx prop with `function` key
29
+ * onyxProp: {
30
+ * key: ({reportId}) => ONYXKEYS.ACCOUNT,
31
+ * },
32
+ * ```
33
+ */
34
+ type BaseMappingKey<
35
+ TComponentProps,
36
+ TOnyxProps,
37
+ TOnyxProp extends keyof TOnyxProps,
38
+ TOnyxKey extends OnyxKey,
39
+ TOnyxValue
40
+ > = IsEqual<TOnyxValue, TOnyxProps[TOnyxProp]> extends true
41
+ ? {
42
+ key: TOnyxKey | ((props: Omit<TComponentProps, keyof TOnyxProps>) => TOnyxKey);
43
+ }
44
+ : never;
45
+
46
+ /**
47
+ * Represents the string `key` and `selector` mapping options between an Onyx key and the component's prop.
48
+ *
49
+ * The function signature and return type of `selector` must match with the type of the component's prop,
50
+ * otherwise an error will be thrown.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * // Onyx prop with `string` key and selector
55
+ * onyxProp: {
56
+ * key: ONYXKEYS.ACCOUNT,
57
+ * selector: (value: Account | null): string => value?.id ?? '',
58
+ * },
59
+ * ```
60
+ */
61
+ type BaseMappingStringKeyAndSelector<
62
+ TComponentProps,
63
+ TOnyxProps,
64
+ TOnyxProp extends keyof TOnyxProps,
65
+ TOnyxKey extends OnyxKey
66
+ > = {
67
+ key: TOnyxKey;
68
+ selector: Selector<TOnyxKey, TOnyxProps[TOnyxProp]>;
69
+ };
70
+
71
+ /**
72
+ * Represents the function `key` and `selector` mapping options between an Onyx key and the component's prop.
73
+ *
74
+ * The function signature and return type of `selector` must match with the type of the component's prop,
75
+ * otherwise an error will be thrown.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // Onyx prop with `function` key and selector
80
+ * onyxProp: {
81
+ * key: ({reportId}) => ONYXKEYS.ACCOUNT,
82
+ * selector: (value: Account | null) => value?.id ?? '',
83
+ * },
84
+ * ```
85
+ */
86
+ type BaseMappingFunctionKeyAndSelector<
87
+ TComponentProps,
88
+ TOnyxProps,
89
+ TOnyxProp extends keyof TOnyxProps,
90
+ TOnyxKey extends OnyxKey
91
+ > = {
92
+ key: (props: Omit<TComponentProps, keyof TOnyxProps>) => TOnyxKey;
93
+ selector: Selector<TOnyxKey, TOnyxProps[TOnyxProp]>;
94
+ };
95
+
96
+ /**
97
+ * Represents the mapping options between an Onyx key and the component's prop with all its possibilities.
98
+ */
99
+ type Mapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey> = BaseMapping<
100
+ TComponentProps,
101
+ TOnyxProps
102
+ > &
103
+ (
104
+ | BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxEntry<KeyValueMapping[TOnyxKey]>>
105
+ | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
106
+ | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
107
+ );
108
+
109
+ /**
110
+ * Represents the mapping options between an Onyx collection key without suffix and the component's prop with all its possibilities.
111
+ */
112
+ type CollectionMapping<
113
+ TComponentProps,
114
+ TOnyxProps,
115
+ TOnyxProp extends keyof TOnyxProps,
116
+ TOnyxKey extends CollectionKeyBase
117
+ > = BaseMapping<TComponentProps, TOnyxProps> &
118
+ (
119
+ | BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxCollection<KeyValueMapping[TOnyxKey]>>
120
+ | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
121
+ | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
122
+ );
123
+
124
+ /**
125
+ * Represents an union type of all the possible Onyx key mappings.
126
+ * Each `OnyxPropMapping` will be associated with its respective Onyx key, ensuring different type-safety for each object.
127
+ */
128
+ type OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps> = {
129
+ [TOnyxKey in OnyxKey]: Mapping<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>;
130
+ }[OnyxKey];
131
+
132
+ /**
133
+ * Represents an union type of all the possible Onyx collection keys without suffix mappings.
134
+ * Each `OnyxPropCollectionMapping` will be associated with its respective Onyx key, ensuring different type-safety for each object.
135
+ */
136
+ type OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps> = {
137
+ [TOnyxKey in CollectionKeyBase]: CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>;
138
+ }[CollectionKeyBase];
139
+
140
+ /**
141
+ * This is a higher order component that provides the ability to map a state property directly to
142
+ * something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
143
+ * will automatically change to reflect the new data.
144
+ */
145
+ declare function withOnyx<TComponentProps, TOnyxProps>(
146
+ mapping: {
147
+ [TOnyxProp in keyof TOnyxProps]:
148
+ | OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp>
149
+ | OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp>;
150
+ },
151
+ ): (component: React.ComponentType<TComponentProps>) => React.ComponentType<Omit<TComponentProps, keyof TOnyxProps>>;
152
+
153
+ export default withOnyx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "1.0.59",
3
+ "version": "1.0.60",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",
@@ -31,6 +31,7 @@
31
31
  "react-native": "native.js",
32
32
  "main": "native.js",
33
33
  "browser": "web.js",
34
+ "types": "lib/index.d.ts",
34
35
  "scripts": {
35
36
  "lint": "eslint .",
36
37
  "lint-tests": "eslint tests/**",
@@ -50,6 +51,7 @@
50
51
  "@react-native-community/eslint-config": "^2.0.0",
51
52
  "@testing-library/jest-native": "^3.4.2",
52
53
  "@testing-library/react-native": "^7.0.2",
54
+ "@types/react": "^18.2.14",
53
55
  "babel-eslint": "^10.1.0",
54
56
  "babel-jest": "^26.2.2",
55
57
  "babel-loader": "^8.2.5",
@@ -68,6 +70,7 @@
68
70
  "react-native-performance": "^2.0.0",
69
71
  "react-native-quick-sqlite": "^8.0.0-beta.2",
70
72
  "react-test-renderer": "18.1.0",
73
+ "type-fest": "^3.12.0",
71
74
  "webpack": "^5.72.1",
72
75
  "webpack-cli": "^4.9.2",
73
76
  "webpack-merge": "^5.8.0"