Skip to content
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

Improve Flow typing of 'navigation' props, rework how params are extracted #3437

Closed
wants to merge 3 commits into from

Conversation

borisyankov
Copy link
Contributor

Prerequisite for #3422

More details in each commit.

  • connect: Use navigation.getParam() instead of navigation.state.params
  • Replace navigation.state.params with getParam
  • flow: Use better types for navigation properties

…ams'

This change preserves the behavior and is almost a pure refactor.

Using `getParam` is the preferred way of accessing the navigation's state
parameters and has some advantages, as documented here:
https://reactnavigation.org/docs/en/params.html

`navigation.state.params` can be `null` if no parameters are passed.
While we do not do that in our code, the types, nor our code is
acknowledging that possibility.

`getParam` will always execute and we can optionally provide a
default value when none exists. Sometimes, not giving a default
value is good enough.

Prime example of how this approach simplifies our code (if written
correctly) is the `RealmScreen.js` file:
 * we don't actually need to verify if `navigation` is defined,
   it always is, when the component is used as a navigation screen
 * we don't need to check if `navigation.state.param` is defined,
   as `getParam` will do that for us
 * `getParam` also provides us the default value
I had some doubts about this change before doing some research and
experimentation with Flow typing our previous code. It looks like
we will lose some Flow typing by using this approach. Not really.

First things first. Our Flow types were completely bogus.
They look correct but they are not helping. They look like this:

```
navigation: NavigationScreenProp<*> & {
  state: {
    params: {
      someValue: SomeType,
    },
  },
},
```

If one renames the `someValue` name in code but not in this type,
they will quickly realize Flow does not catch that. So we are just
pretentind to be typing the parameters.
Use the more precise typing for `navigation` which is:
`navigation: NavigationScreenProp<NavigationStateRoute>`

This would actually catch errors if we did have any, as now the
value is properly typed.

We do not lose any typing from the:
```
state: {
  params: {
    narrow: Narrow,
  },
},
```
As the `<*>` would allow anything as alternative.

I experimented with typing that did not work, similar to:
```
export type NavigationParams<T> = NavigationScreenProp<{
  ...NavigationStateRoute,
  params: T,
}>;
```
@borisyankov
Copy link
Contributor Author

@gnprice ready for review/discussion/merge.

@gnprice
Copy link
Member

gnprice commented Apr 1, 2019

Thanks @borisyankov ! These navigation types have certainly bugged me for a while.

I don't love the getParam style, because it seems like it'll be much harder to get proper types on than the params style. The latter style, it clearly should be possible in principle to describe the types of in Flow, even if we currently don't and perhaps the libdefs we have in flow-typed/npm/ currently don't make it possible. Specifically, params is some particular object type, and in fact it corresponds (when everything's correct!) to the type of the actual object we pass in the corresponding action creator in navActions.js.

But the fact that navigation.getParam('messageId') in EmojiPickerScreen returns number while navigation.getParam('message') in LightboxScreen returns Message... expressing that fact, in the type system in a checkable way, just seems impossible.

Given that we don't currently have working type-checking on these, I could see making the change, knowing that we'd end up changing back if we later see an opportunity to get working type-checking. But I'd want to better understand what we're gaining from the change.

Re RealmScreen.js:

 * we don't actually need to verify if `navigation` is defined,
   it always is, when the component is used as a navigation screen
 * we don't need to check if `navigation.state.param` is defined,
   as `getParam` will do that for us

What we do in most components is just directly get properties off of props.navigation.state.params. If we've somehow reached the component without appropriate navigation, that can blow up... but the component is already written to assume that we get there in a certain way, and if that assumption fails then it's best to fail early anyway rather than get into the interior of the component's code and fail in some unpredictable way midway through. So we can just simplify to

  initialRealm: props.navigation.state.params.realm || '',

independent of this change.

@gnprice
Copy link
Member

gnprice commented Apr 1, 2019

BTW as it happens I did some work on these types last week, as part of my cleaning up of most of the remaining Object types. See master...gnprice:nav-params-types for the unpolished rough branch -- before ending the day I cleaned up the other changes in the branch and merged them (as dd03939^..d298669), but didn't get to those.

If it'll help with #3422, I can go back in the next day or two and finish and merge those changes. What was the issue you were seeing?

@gnprice
Copy link
Member

gnprice commented Apr 17, 2019

As promised above, a couple of weeks ago I went and made a bunch of cleanups and fixes to the navigation types; see 05bfc6c^..7293860.

I think that resolves what this PR was aiming for, and without sacrificing any type-checking (as getParam does); so closing. If there's an aspect of this PR you think remains useful, please go ahead and open a new one atop master. Thanks again!

@gnprice gnprice closed this Apr 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants