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

tighten QueryTuple to indicate observable fields may be absent #5935

Merged
merged 2 commits into from
Feb 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/react/data/QueryData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
QueryCurrentObservable,
QueryTuple,
QueryLazyOptions,
ObservableQueryFields
ObservableQueryFields,
LazyQueryResult
} from '../types/types';
import { OperationData } from './OperationData';

Expand Down Expand Up @@ -68,7 +69,7 @@ export class QueryData<TData, TVariables> extends OperationData {
networkStatus: NetworkStatus.ready,
called: false,
data: undefined
} as QueryResult<TData, TVariables>
}
]
: [this.runLazyQuery, this.execute()];
}
Expand All @@ -84,13 +85,13 @@ export class QueryData<TData, TVariables> extends OperationData {
queryResult,
lazy = false,
}: {
queryResult: QueryResult<TData, TVariables>;
queryResult: QueryResult<TData, TVariables> | LazyQueryResult<TData, TVariables>;
Copy link
Author

@benmosher benmosher Feb 11, 2020

Choose a reason for hiding this comment

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

I know this is redundant (since LazyQueryResult<D,V> already includes QueryResult<D,V>) but this felt like a reasonable duplication in the interest of clarity (since both lazy and non-lazy paths go through here).

lazy?: boolean;
}) {
this.isMounted = true;

if (!lazy || this.runLazy) {
this.handleErrorOrCompleted(queryResult);
this.handleErrorOrCompleted(queryResult as QueryResult<TData, TVariables>);
Copy link
Author

Choose a reason for hiding this comment

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

!lazy || this.runLazy does properly enforce this type cast at runtime, AFAICT. but TS compiler doesn't know that.


// When the component is done rendering stored query errors, we'll
// remove those errors from the `ObservableQuery` query store, so they
Expand Down
27 changes: 25 additions & 2 deletions src/react/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export interface QueryResult<TData = any, TVariables = OperationVariables>
error?: ApolloError;
loading: boolean;
networkStatus: NetworkStatus;
called: boolean;
called: true;
Copy link
Author

Choose a reason for hiding this comment

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

assuming this field does not mean anything outside of lazy results, I believe this is correct now, as of the preceding commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hi,

I was wondering why you think this is correct.
By looking at the code I can see that called can definitely be false:

I spotted this strange type declaration because I'm getting an @typescript-eslint/no-unnecessary-condition warning on if (result.called) { ... The warning is correct but the type is not.

In my interpretation called should be false if the lazy initialization is not yet called. This how it seems to be implemented.
Is this perhaps deprecated? Did you intend to override called back to boolean for LazyQueryResult?

Copy link
Member

Choose a reason for hiding this comment

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

The type of called was relaxed to boolean again in v3.5.8, thanks to #9328.

Copy link
Author

Choose a reason for hiding this comment

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

it's been ages, but I think you're right that I meant to have LazyQueryResult set called: boolean. sorry for the bug!

}

export interface QueryDataOptions<TData = any, TVariables = OperationVariables>
Expand Down Expand Up @@ -123,9 +123,32 @@ export interface QueryLazyOptions<TVariables> {
context?: Context;
}

type UnexecutedLazyFields = {
loading: false;
networkStatus: NetworkStatus.ready;
called: false;
data: undefined;
}

type Impartial<T> = {
Copy link
Author

Choose a reason for hiding this comment

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

named as such as a complement to Partial<T>. I am totally fine with a less cute name if you have one in mind.

[P in keyof T]?: never;
}

type AbsentLazyResultFields =
Omit<
Impartial<QueryResult<unknown, unknown>>,
keyof UnexecutedLazyFields>

type UnexecutedLazyResult =
UnexecutedLazyFields & AbsentLazyResultFields

export type LazyQueryResult<TData, TVariables> =
| UnexecutedLazyResult
| QueryResult<TData, TVariables>;

export type QueryTuple<TData, TVariables> = [
Copy link
Author

Choose a reason for hiding this comment

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

FWIW: was tempted to rename this to LazyQueryTuple but I didn't want to rock the boat too much.

(options?: QueryLazyOptions<TVariables>) => void,
QueryResult<TData, TVariables>
LazyQueryResult<TData, TVariables>
];

/* Mutation types */
Expand Down