-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
change selector return type #482
change selector return type #482
Conversation
Is there an App issue to link to? Even if the change is good is there some issue explaining why this change is needed now? |
Context here @chiragsalian, but I think it's good to run this by Callstack (or SWM) first. |
Asked here. |
Cool, thank you |
lib/withOnyx.d.ts
Outdated
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, Partial<KeyValueMapping[TOnyxKey]>, TOnyxKey> | ||
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, Partial<KeyValueMapping[TOnyxKey]>, TOnyxKey> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, Partial<KeyValueMapping[TOnyxKey]>, TOnyxKey> | |
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, Partial<KeyValueMapping[TOnyxKey]>, TOnyxKey> | |
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | |
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> |
@tienifr We have two issues here:
-
By changing
TOnyxProps[TOnyxProp]
toPartial<KeyValueMapping[TOnyxKey]>
we lose all type equality check between the components'OnyxProps
andwithOnyx
mapping, which means that we could type anything in the Onyx prop and the selector wouldn't be able to check if its return type matches with the corresponding Onyx prop. -
Also, by doing
Partial<KeyValueMapping[TOnyxKey]>
you are limiting the selector's return to be an object with optional properties of that Onyx value, which is not always the case.When we have a combination of a collection key and a
selector
, thewithOnyx
will runselector
function for each entry of that collection and build a collection object with the results of allselector
executions, for example:type ContactMethodDetailsPageOnyxProps = { policiesIDs: OnyxCollection<string>; }; ... export default withOnyx<ContactMethodDetailsPageProps, ContactMethodDetailsPageOnyxProps>({ policiesIDs: { key: ONYXKEYS.COLLECTION.POLICY, selector: (data) => data?.id ?? '', // this is valid and will make policies return a collection of ids }, })(ContactMethodDetailsPage);
To improve these typings, my suggestion is:
- Add this type in
lib/types.d.ts
which will make possible extracting the value of a Onyx collection:... type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue | null>>; /** * Utility type to extract `TOnyxValue` from `OnyxCollection<TOnyxValue>`. */ type ExtractOnyxCollectionValue<TOnyxCollection> = TOnyxCollection extends NonNullable<OnyxCollection<infer U>> ? U : never; ...
- Use it in
CollectionMapping
:/** * Represents the mapping options between an Onyx collection key without suffix and the component's prop with all its possibilities. */ type CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends CollectionKeyBase> = BaseMapping<TComponentProps, TOnyxProps> & CollectionBaseMapping<TOnyxKey> & ( | BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxCollection<KeyValueMapping[TOnyxKey]>> | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> );
This way we can ensure the type equality checks will still work and get rid of these issues when using the selector
. For your case in this discussion, final solution would be like this:
type ContactMethodDetailsPageOnyxProps = {
...
policies: OnyxCollection<Pick<Policy, 'id' | 'ownerAccountID'>>;
};
...
export default withOnyx<ContactMethodDetailsPageProps, ContactMethodDetailsPageOnyxProps>({
...
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
selector: (data) => ({id: data?.id ?? '', ownerAccountID: data?.ownerAccountID}),
},
})(ContactMethodDetailsPage);
@fabioh8010 I'd love your idea above^. It works for me. Using |
lib/withOnyx.d.ts
Outdated
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | ||
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | |
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | |
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> | |
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> |
You changed the wrong Mapping 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah my fault 🤦♂️ .
lib/withOnyx.d.ts
Outdated
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> | ||
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> | |
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProps[TOnyxProp], TOnyxKey> | |
| BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> | |
| BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, ExtractOnyxCollectionValue<TOnyxProps[TOnyxProp]>, TOnyxKey> |
Thanks for pointing that out. I updated the PR @fabioh8010 |
Hmm actually it doesn't work at all, not due to TS checks, but I see that we use |
@youssef-lr Do you mind sharing the code that isn't working? I tested here and the types are correct. ![]() |
Hm I think the changes in react-native-onyx are not being reflected for me locally, here's what I did:
Am I missing something? |
@youssef-lr After doing |
Yeah I was just doing that now |
They are updated..maybe it's just an issue with my editor. Thanks for checking! |
Any idea why the selector takes a single policy instead of all the policies from the collection? Probably out of scope here, but I was under the assumption the param of the selector should be all of the policies Edit: I think it has always been like this..I will bring up a discussion in Slack as I'm curious if we'd have a need for a selector returning all policies and then we can use a |
Co-authored-by: Błażej Kustra <46095609+blazejkustra@users.noreply.github.com>
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
I have read the CLA Document and I hereby sign the CLA |
@youssef-lr When we have this combination of a collection key and |
I wonder if we could update that such as if the selector returns |
So here's a use case I'm thinking of, suppose we have a component that only needs a subset of a collection to subscribe to, we don't want re-renders if other items from that collection changes, I think only passing the items to the component would be beneficial here. Buuut, I suppose filtering out |
Details
Related Issues
GH_LINK
Automated Tests
Manual Tests
Author Checklist
### Related Issues
section aboveTests
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
MacOS: Desktop