Skip to content

Commit

Permalink
Add type assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
roryabraham committed Feb 14, 2025
1 parent 8a576be commit 502b3c6
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
32 changes: 31 additions & 1 deletion src/libs/actions/OnyxDerived.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import OnyxUtils from 'react-native-onyx/dist/OnyxUtils';
import type {NonEmptyTuple, ValueOf} from 'type-fest';
import {isThread} from '@libs/ReportUtils';
import CONST from '@src/CONST';
import type {GetOnyxTypeForKey, OnyxDerivedValuesMapping, OnyxKey} from '@src/ONYXKEYS';
import type {GetOnyxTypeForKey, OnyxDerivedKey, OnyxDerivedValuesMapping, OnyxKey} from '@src/ONYXKEYS';
import ONYXKEYS from '@src/ONYXKEYS';
import type AssertTypesEqual from '@src/types/utils/AssertTypesEqual';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import type SymmetricDifference from '@src/types/utils/SymmetricDifference';

/**
* A derived value configuration describes:
Expand Down Expand Up @@ -82,6 +84,9 @@ function getOnyxValues<Keys extends readonly OnyxKey[]>(keys: Keys): Promise<{[I
return Promise.all(keys.map((key) => OnyxUtils.get(key))) as Promise<{[Index in keyof Keys]: GetOnyxTypeForKey<Keys[Index]>}>;
}

/**
* Initialize all Onyx derived values, store them in Onyx, and setup listeners to update them when dependencies change.
*/
function init() {
for (const [key, {compute, dependencies}] of ObjectUtils.typedEntries(ONYX_DERIVED_VALUES)) {
// Create an array to hold the current values for each dependency.
Expand Down Expand Up @@ -136,3 +141,28 @@ function init() {
}

export default init;

// Note: we can't use `as const satisfies...` for ONYX_DERIVED_VALUES without losing type specificity.
// So these type assertions are here to help enforce that ONYX_DERIVED_VALUES has all the keys and the correct types,
// according to the type definitions for derived keys in ONYXKEYS.ts.
type MismatchedDerivedKeysError =
`Error: ONYX_DERIVED_VALUES does not match ONYXKEYS.DERIVED or OnyxDerivedValuesMapping. The following keys are present in one or the other, but not both: ${SymmetricDifference<
keyof typeof ONYX_DERIVED_VALUES,
OnyxDerivedKey
>}`;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type KeyAssertion = AssertTypesEqual<keyof typeof ONYX_DERIVED_VALUES, OnyxDerivedKey, MismatchedDerivedKeysError>;

type ExpectedDerivedValueComputeReturnTypes = {
[Key in keyof OnyxDerivedValuesMapping]: OnyxEntry<OnyxDerivedValuesMapping[Key]>;
};
type ActualDerivedValueComputeReturnTypes = {
[Key in keyof typeof ONYX_DERIVED_VALUES]: ReturnType<(typeof ONYX_DERIVED_VALUES)[Key]['compute']>;
};
type MismatchedDerivedValues = {
[Key in keyof ExpectedDerivedValueComputeReturnTypes]: ExpectedDerivedValueComputeReturnTypes[Key] extends ActualDerivedValueComputeReturnTypes[Key] ? never : Key;
}[keyof ExpectedDerivedValueComputeReturnTypes];
type MismatchedDerivedValuesError =
`Error: ONYX_DERIVED_VALUES does not match OnyxDerivedValuesMapping. The following configs have compute functions that do not return the correct type according to OnyxDerivedValuesMapping: ${MismatchedDerivedValues}`;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type ComputeReturnTypeAssertion = AssertTypesEqual<MismatchedDerivedValues, never, MismatchedDerivedValuesError>;
3 changes: 3 additions & 0 deletions src/types/utils/SymmetricDifference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type SymmetricDifference<A, B> = Exclude<A, B> | Exclude<B, A>;

export default SymmetricDifference;

0 comments on commit 502b3c6

Please sign in to comment.