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

flow: Annotate some more exports. #4927

Merged
merged 4 commits into from
Aug 5, 2021

Conversation

chrisbobbe
Copy link
Contributor

Toward #4907.

These are the four items I'd flagged as "tricky." Here, I follow Greg's suggestions for handling them at #4907 (comment). As it turns out, some of them are not all that tricky! 🙂

@chrisbobbe chrisbobbe changed the title Annotate some more exports. flow: Annotate some more exports. Jul 29, 2021
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Comments below.

@@ -102,7 +111,7 @@ export const fetchMessages = (fetchArgs: {|
anchor: number,
numBefore: number,
numAfter: number,
|}) => async (dispatch: Dispatch, getState: GetState): Promise<Message[]> => {
|}): ThunkAction<Promise<Array<Message>>> => async (dispatch, getState): Promise<Message[]> => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can simplify a bit by dropping the inner Promise<Message[]> annotation, which is now redundant

(There are one or two others like this, basically where the return type was something more interesting than void or Promise<void>.)

Also could use the [] shorthand here, as we did in that inner annotation.

@@ -25,7 +25,7 @@ describe('accountsReducer', () => {
expect(
accountsReducer(
deepFreeze([account1, account2, account3]),
deepFreeze({ ...eg.action.realm_init, zulipVersion: newZulipVersion }),
deepFreeze({ ...eg.realmInitAction, zulipVersion: newZulipVersion }),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like these new names -- I'd much rather avoid proliferating different names like this. The good thing about the name eg.action.realm_init is that REALM_INIT is already a name that exists in the code, in lines like case REALM_INIT: in reducers. (Maybe it'd even be better if we called it eg.action.REALM_INIT, but that'd be a change orthogonal to this typing change.)

The name RealmInitAction does exist in actionTypes.js, but that didn't matter so much as long as it was an unexported local name that was used just once 🙂

Is the motivation for these names to put the definitions at the top level of the module, in order to add annotations? I'd hope we can annotate just by casting:

export const action = deepFreeze({
  account_switch: ({
    type: ACCOUNT_SWITCH,
    index: 0,
  }: AccountSwitchAction),

(Oh and I guess either ditching the deepFreeze, or moving it inward:

export const action = Object.freeze({
  account_switch: deepFreeze({
    type: ACCOUNT_SWITCH,
    index: 0,
  }: AccountSwitchAction),

because it isn't transparent to the types-first quick pass.)

If that's too much for types-first to see through, we can always just put an object-type annotation at the top level:

export const action: {|
  account_switch: AccountSwitchAction,
  // …
|} = deepFreeze({
  account_switch: {
    type: ACCOUNT_SWITCH,
    index: 0,
  },

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the motivation for these names to put the definitions at the top level of the module, in order to add annotations?

It was. But looking back at your message on CZO, I see I misread what you wanted me to try. 😛 I'd thought you were asking for the members of eg.action to be exported individually, IOW, to pull them out into their own exported variables. Now I see you were talking about exporting the types themselves, in a different file, like RealmInitAction.

@@ -97,7 +98,7 @@ export const apiGet = async (
route: string,
params: UrlParams = {},
isSilent: boolean = false,
) =>
): Promise<empty> =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the one hand, this is just making explicit what was already the case, so there's no regression here and I don't want to block it on any more significant cleanup that would be more work.

But as we're adding these, I would like to avoid having it look like we're saying these are just honestly the types. There is something to fix here, and when looking at this function's interface the reader should see that. One quick solution is to propagate the "beware" jsdoc comment that I put on apiCall in that previous commit.

Ooh, or better: instead of empty we can write $FlowFixMe. … Hmm, no, that's better in one way, but it has the major disadvantage that it won't automatically get flagged when we take that RN upgrade that lets fetch have a real type.

Anyway, propagating the comment would be good enough. Another alternative would be to add a line like type FixmeUntypedFetchResult = empty, and say Promise<FixmeUntypedFetchResult>.

@@ -7,7 +7,7 @@ import { apiDelete } from '../apiFetch';
*
* @param mobileOS - Choose the server-side API intended for iOS or Android clients.
*/
export default (auth: Auth, mobileOS: 'ios' | 'android', token: string) => {
export default (auth: Auth, mobileOS: 'ios' | 'android', token: string): Promise<empty> => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for this one and savePushToken, it looks like we don't actually inspect the returned result at all -- so this could just be Promise<mixed>.

@@ -3,7 +3,7 @@ import userAgent from '../utils/userAgent';

// check with server if current mobile app is compatible with latest backend
// compatibility fails only if server responds with 400 (but not with 200 or 404)
export default () =>
export default (): Promise<empty> =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be Promise<{ status: number, ... }>.

@@ -40,7 +40,8 @@ export const apiFetch = async (
auth: Auth,
route: string,
params: $Diff<$Exact<RequestOptions>, {| headers: mixed |}>,
) => fetch(new URL(`/${apiVersion}/${route}`, auth.realm).toString(), getFetchParams(auth, params));
): Promise<empty> =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one actually doesn't need to be exported at all! So that's the simplest fix for this one.

chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Aug 4, 2021
To bring us closer to annotating all our exports, for zulip#4907.

Most of these use a new `FixmeUntypedFetchResult` type; see its
jsdoc.

`apiFetch` can be unexported; so, do that, removing the need for an
annotation [1].

`savePushToken` and `forgetPushToken` get `Promise<mixed>` because
we don't actually inspect the returned result at all [2].

`checkCompatibility` gets `Promise<{ status: number, ... }>` because
we'll always be looking at the response status [3].

[1] zulip#4927 (comment)
[2] zulip#4927 (comment)
[3] zulip#4927 (comment)
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Aug 4, 2021
Following Greg's recommendation at
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Flow.20types-first/near/1237928.

This will help move us along toward Flow's new "Types-First" mode;
switching entirely is zulip#4907.

We move the `deepFreeze` inward, onto each individual member of
`eg.action`, because it isn't transparent to the types-first quick
pass; see
  zulip#4927 (comment).
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Aug 4, 2021
To bring us closer to annotating all our exports, for zulip#4907.

Most of these use a new `FixmeUntypedFetchResult` type; see its
jsdoc.

`apiFetch` can be unexported; so, do that, removing the need for an
annotation [1].

`savePushToken` and `forgetPushToken` get `Promise<mixed>` because
we don't actually inspect the returned result at all [2].

`checkCompatibility` gets `Promise<{ status: number, ... }>` because
we'll always be looking at the response status [3].

[1] zulip#4927 (comment)
[2] zulip#4927 (comment)
[3] zulip#4927 (comment)
@chrisbobbe
Copy link
Contributor Author

Thanks for the review! Revision pushed.

Following Greg's recommendation at
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Flow.20types-first/near/1237907.

Done by using the codemod [1] with the following command, then
removing irrelevant changes, then making the annotations a bit more
concise.

  yarn flow codemod annotate-exports --write --repeat \
    --log-level info src/ 2>out3.log

This will help move us along toward Flow's new "Types-First" mode;
switching entirely is zulip#4907.

[1] https://flow.org/en/docs/cli/annotate-exports/
Following Greg's recommendation at
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Flow.20types-first/near/1237928.

This will help move us along toward Flow's new "Types-First" mode;
switching entirely is zulip#4907.

We move the `deepFreeze` inward, onto each individual member of
`eg.action`, because it isn't transparent to the types-first quick
pass; see
  zulip#4927 (comment).
…track.

Following Greg's recommendation at
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Flow.20types-first/near/1237936.

This will help move us along toward Flow's new "Types-First" mode;
switching entirely is zulip#4907.
To bring us closer to annotating all our exports, for zulip#4907.

Most of these use a new `FixmeUntypedFetchResult` type; see its
jsdoc.

`apiFetch` can be unexported; so, do that, removing the need for an
annotation [1].

`savePushToken` and `forgetPushToken` get `Promise<mixed>` because
we don't actually inspect the returned result at all [2].

`checkCompatibility` gets `Promise<{ status: number, ... }>` because
we'll always be looking at the response status [3].

[1] zulip#4927 (comment)
[2] zulip#4927 (comment)
[3] zulip#4927 (comment)
@gnprice
Copy link
Member

gnprice commented Aug 5, 2021

Thanks! Looks good -- merging.

@gnprice gnprice merged commit 8876361 into zulip:master Aug 5, 2021
@chrisbobbe chrisbobbe deleted the pr-tricky-annotations branch November 4, 2021 21:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants