Skip to content

Commit

Permalink
Merge pull request #542 from fabioh8010/feature/ts-migration/withOnyx
Browse files Browse the repository at this point in the history
[TS migration] Migrate `withOnyx.js` to TypeScript
  • Loading branch information
NikkiWines authored May 29, 2024
2 parents b6a108d + abbbd76 commit 3a06c8c
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 183 deletions.
6 changes: 4 additions & 2 deletions API-INTERNAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ whatever it is we attempted to do.</p>
</dd>
<dt><a href="#removeNullValues">removeNullValues()</a> ⇒</dt>
<dd><p>Removes a key from storage if the value is null.
Otherwise removes all nested null values in objects and returns the object</p>
Otherwise removes all nested null values in objects,
if shouldRemoveNestedNulls is true and returns the object.</p>
</dd>
<dt><a href="#prepareKeyValuePairsForStorage">prepareKeyValuePairsForStorage()</a> ⇒</dt>
<dd><p>Storage expects array like: [[&quot;@MyApp_user&quot;, value_1], [&quot;@MyApp_key&quot;, value_2]]
Expand Down Expand Up @@ -367,7 +368,8 @@ Notifies subscribers and writes current value to cache

## removeNullValues() ⇒
Removes a key from storage if the value is null.
Otherwise removes all nested null values in objects and returns the object
Otherwise removes all nested null values in objects,
if shouldRemoveNestedNulls is true and returns the object.

**Kind**: global function
**Returns**: The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
Expand Down
28 changes: 14 additions & 14 deletions lib/OnyxUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,32 @@
import {deepEqual} from 'fast-equals';
import lodashClone from 'lodash/clone';
import type {ValueOf} from 'type-fest';
import DevTools from './DevTools';
import * as Logger from './Logger';
import type Onyx from './Onyx';
import cache from './OnyxCache';
import * as Str from './Str';
import * as PerformanceUtils from './PerformanceUtils';
import Storage from './storage';
import utils from './utils';
import * as Str from './Str';
import unstable_batchedUpdates from './batch';
import DevTools from './DevTools';
import Storage from './storage';
import type {
DeepRecord,
Mapping,
CollectionKey,
CollectionKeyBase,
DeepRecord,
DefaultConnectCallback,
DefaultConnectOptions,
KeyValueMapping,
Mapping,
NullableKeyValueMapping,
OnyxCollection,
OnyxEntry,
OnyxKey,
OnyxValue,
Selector,
WithOnyxInstanceState,
OnyxCollection,
WithOnyxConnectOptions,
DefaultConnectOptions,
OnyxEntry,
KeyValueMapping,
DefaultConnectCallback,
} from './types';
import type Onyx from './Onyx';
import utils from './utils';
import type {WithOnyxState} from './withOnyx/types';

// Method constants
const METHOD = {
Expand Down Expand Up @@ -195,7 +195,7 @@ function batchUpdates(updates: () => void): Promise<void> {
function reduceCollectionWithSelector<TKey extends CollectionKeyBase, TMap, TReturn>(
collection: OnyxCollection<KeyValueMapping[TKey]>,
selector: Selector<TKey, TMap, TReturn>,
withOnyxInstanceState: WithOnyxInstanceState<TMap> | undefined,
withOnyxInstanceState: WithOnyxState<TMap> | undefined,
): Record<string, TReturn> {
return Object.entries(collection ?? {}).reduce((finalCollection: Record<string, TReturn>, [key, item]) => {
// eslint-disable-next-line no-param-reassign
Expand Down
25 changes: 13 additions & 12 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import type {ConnectOptions, OnyxUpdate} from './Onyx';
import Onyx from './Onyx';
import type {OnyxUpdate, ConnectOptions} from './Onyx';
import type {CustomTypeOptions, OnyxCollection, OnyxEntry, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState, OnyxValue} from './types';
import type {UseOnyxResult, FetchStatus, ResultMetadata} from './useOnyx';
import type {CustomTypeOptions, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector} from './types';
import type {FetchStatus, ResultMetadata, UseOnyxResult} from './useOnyx';
import useOnyx from './useOnyx';
import withOnyx from './withOnyx';
import type {WithOnyxState} from './withOnyx/types';

export default Onyx;
export {withOnyx, useOnyx};
export {useOnyx, withOnyx};
export type {
ConnectOptions,
CustomTypeOptions,
FetchStatus,
KeyValueMapping,
NullishDeep,
OnyxCollection,
OnyxEntry,
OnyxUpdate,
ConnectOptions,
NullishDeep,
KeyValueMapping,
OnyxKey,
Selector,
WithOnyxInstanceState,
UseOnyxResult,
OnyxUpdate,
OnyxValue,
FetchStatus,
ResultMetadata,
Selector,
UseOnyxResult,
WithOnyxState,
};
20 changes: 6 additions & 14 deletions lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {Component} from 'react';
import type {Merge} from 'type-fest';
import type {BuiltIns} from 'type-fest/source/internal';
import type OnyxUtils from './OnyxUtils';
import type {WithOnyxInstance, WithOnyxState} from './withOnyx/types';

/**
* Utility type that excludes `null` from the type `TValue`.
Expand Down Expand Up @@ -148,7 +148,7 @@ type NullableKeyValueMapping = {
* The type `TKey` extends `OnyxKey` and it is the key used to access a value in `KeyValueMapping`.
* `TReturnType` is the type of the returned value from the selector function.
*/
type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>, state: WithOnyxInstanceState<TOnyxProps>) => TReturnType;
type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>, state?: WithOnyxState<TOnyxProps>) => TReturnType;

/**
* Represents a single Onyx entry, that can be either `TOnyxValue` or `null` / `undefined` if it doesn't exist.
Expand Down Expand Up @@ -252,11 +252,6 @@ type NullishObjectDeep<ObjectType extends object> = {
[KeyType in keyof ObjectType]?: NullishDeep<ObjectType[KeyType]> | null;
};

/**
* Represents withOnyx's internal state, containing the Onyx props and a `loading` flag.
*/
type WithOnyxInstanceState<TOnyxProps> = (TOnyxProps & {loading: boolean}) | undefined;

/**
* Represents a mapping between Onyx collection keys and their respective values.
*
Expand All @@ -274,11 +269,6 @@ type Collection<TKey extends CollectionKeyBase, TMap, TValue> = {
: never;
};

type WithOnyxInstance = Component<unknown, WithOnyxInstanceState<NullableKeyValueMapping>> & {
setStateProxy: (cb: (state: Record<string, OnyxCollection<KeyValueMapping[OnyxKey]>>) => OnyxValue<OnyxKey>) => void;
setWithOnyxState: (statePropertyName: OnyxKey, value: OnyxValue<OnyxKey>) => void;
};

/** Represents the base options used in `Onyx.connect()` method. */
type BaseConnectOptions = {
initWithStoredValues?: boolean;
Expand Down Expand Up @@ -400,6 +390,9 @@ type InitOptions = {
debugSetState?: boolean;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type GenericFunction = (...args: any[]) => any;

export type {
BaseConnectOptions,
Collection,
Expand All @@ -413,6 +406,7 @@ export type {
DefaultConnectCallback,
DefaultConnectOptions,
ExtractOnyxCollectionValue,
GenericFunction,
InitOptions,
Key,
KeyValueMapping,
Expand All @@ -428,6 +422,4 @@ export type {
OnyxValue,
Selector,
WithOnyxConnectOptions,
WithOnyxInstance,
WithOnyxInstanceState,
};
6 changes: 6 additions & 0 deletions lib/types/modules/react.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type React from 'react';

declare module 'react' {
// eslint-disable-next-line @typescript-eslint/ban-types
function forwardRef<T, P = {}>(render: (props: P, ref: React.ForwardedRef<T>) => React.ReactElement | null): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
}
56 changes: 55 additions & 1 deletion lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,58 @@ function checkCompatibilityWithExistingValue(value: unknown, existingValue: unkn
};
}

export default {isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue};
/**
* Filters an object based on a condition and an inclusion flag.
*
* @param obj - The object to filter.
* @param condition - The condition to apply.
* @param include - If true, include entries that match the condition; otherwise, exclude them.
* @returns The filtered object.
*/
function filterObject<TValue>(obj: Record<string, TValue>, condition: string | string[] | ((entry: [string, TValue]) => boolean), include: boolean): Record<string, TValue> {
const result: Record<string, TValue> = {};
const entries = Object.entries(obj);

for (let i = 0; i < entries.length; i++) {
const [key, value] = entries[i];
let shouldInclude: boolean;

if (Array.isArray(condition)) {
shouldInclude = condition.includes(key);
} else if (typeof condition === 'string') {
shouldInclude = key === condition;
} else {
shouldInclude = condition(entries[i]);
}

if (include ? shouldInclude : !shouldInclude) {
result[key] = value;
}
}

return result;
}

/**
* Picks entries from an object based on a condition.
*
* @param obj - The object to pick entries from.
* @param condition - The condition to determine which entries to pick.
* @returns The object containing only the picked entries.
*/
function pick<TValue>(obj: Record<string, TValue>, condition: string | string[] | ((entry: [string, TValue]) => boolean)): Record<string, TValue> {
return filterObject(obj, condition, true);
}

/**
* Omits entries from an object based on a condition.
*
* @param obj - The object to omit entries from.
* @param condition - The condition to determine which entries to omit.
* @returns The object containing only the remaining entries after omission.
*/
function omit<TValue>(obj: Record<string, TValue>, condition: string | string[] | ((entry: [string, TValue]) => boolean)): Record<string, TValue> {
return filterObject(obj, condition, false);
}

export default {isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue, pick, omit};
Loading

0 comments on commit 3a06c8c

Please sign in to comment.