From 47ad806c7b0c55f1e05dbf276ca87a354ac389e5 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Mon, 13 May 2024 14:48:07 +0200 Subject: [PATCH] create branded `QueryRef` type without exposed properties (#11824) * create branded `QueryReferenceBase` type * update some test types * changeset * split up into new hierarchy starting from QueryRef type * add export * add some type assignability tests * update doc references * toPromise return type * adjust changeset * stabilize flaky test * Update .changeset/late-planets-argue.md Co-authored-by: Jerel Miller * types in tests * adjust notes * fix integration test TS --------- Co-authored-by: Jerel Miller --- .api-reports/api-report-react.md | 164 ++-------- .api-reports/api-report-react_hooks.md | 151 ++-------- .api-reports/api-report-react_internal.md | 75 +++-- .api-reports/api-report.md | 168 ++--------- .changeset/late-planets-argue.md | 23 ++ .circleci/config.yml | 5 +- .size-limits.json | 4 +- config/inlineInheritDoc.ts | 3 +- .../Overrides/UseLoadableQueryResult.js | 6 +- docs/shared/useBackgroundQuery-result.mdx | 2 +- docs/source/api/react/hooks.mdx | 6 +- docs/source/data/suspense.mdx | 4 +- integration-tests/next/package.json | 2 +- .../next/src/app/cc/ApolloWrapper.tsx | 7 +- .../next/src/libs/apolloClient.ts | 4 +- src/__tests__/__snapshots__/exports.ts.snap | 1 + .../__tests__/useBackgroundQuery.test.tsx | 57 ++-- .../hooks/__tests__/useLoadableQuery.test.tsx | 10 +- src/react/hooks/__tests__/useQuery.test.tsx | 2 +- .../__tests__/useQueryRefHandlers.test.tsx | 26 +- src/react/hooks/useBackgroundQuery.ts | 27 +- src/react/hooks/useLoadableQuery.ts | 9 +- src/react/hooks/useQueryRefHandlers.ts | 22 +- src/react/hooks/useReadQuery.ts | 20 +- src/react/internal/cache/QueryReference.ts | 74 ++++- .../cache/__tests__/QueryReference.test.ts | 27 -- .../cache/__tests__/QueryReference.test.tsx | 281 ++++++++++++++++++ src/react/internal/index.ts | 7 +- .../__tests__/createQueryPreloader.test.tsx | 52 ++-- .../query-preloader/createQueryPreloader.ts | 16 +- src/react/types/types.ts | 6 +- src/testing/matchers/index.d.ts | 6 +- src/testing/matchers/toBeDisposed.ts | 19 +- 33 files changed, 666 insertions(+), 620 deletions(-) create mode 100644 .changeset/late-planets-argue.md delete mode 100644 src/react/internal/cache/__tests__/QueryReference.test.ts create mode 100644 src/react/internal/cache/__tests__/QueryReference.test.tsx diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index 2f6814f59eb..00a986ce9ec 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -770,9 +770,6 @@ type FetchMoreFunction = (fetchMor }) => TData; }) => Promise>; -// @public (undocumented) -type FetchMoreOptions = Parameters["fetchMore"]>[0]; - // @public (undocumented) interface FetchMoreQueryOptions { // (undocumented) @@ -813,14 +810,6 @@ interface FragmentMap { // @public (undocumented) type FragmentMatcher = (rootValue: any, typeCondition: string, context: any) => boolean; -// @public (undocumented) -interface FulfilledPromise extends Promise { - // (undocumented) - status: "fulfilled"; - // (undocumented) - value: TValue; -} - // @internal const getApolloCacheMemoryInternals: (() => { cache: { @@ -918,58 +907,6 @@ interface IncrementalPayload { path: Path; } -// @public (undocumented) -class InternalQueryReference { - // Warning: (ae-forgotten-export) The symbol "InternalQueryReferenceOptions" needs to be exported by the entry point index.d.ts - constructor(observable: ObservableQuery, options: InternalQueryReferenceOptions); - // (undocumented) - applyOptions(watchQueryOptions: ObservedOptions): QueryRefPromise; - // Warning: (ae-forgotten-export) The symbol "ObservedOptions" needs to be exported by the entry point index.d.ts - // - // (undocumented) - didChangeOptions(watchQueryOptions: ObservedOptions): boolean; - // (undocumented) - get disposed(): boolean; - // Warning: (ae-forgotten-export) The symbol "FetchMoreOptions" needs to be exported by the entry point index.d.ts - // - // (undocumented) - fetchMore(options: FetchMoreOptions): Promise>; - // Warning: (ae-forgotten-export) The symbol "QueryKey" needs to be exported by the entry point index.d.ts - // - // (undocumented) - readonly key: QueryKey; - // Warning: (ae-forgotten-export) The symbol "Listener" needs to be exported by the entry point index.d.ts - // - // (undocumented) - listen(listener: Listener): () => void; - // (undocumented) - readonly observable: ObservableQuery; - // Warning: (ae-forgotten-export) The symbol "QueryRefPromise" needs to be exported by the entry point index.d.ts - // - // (undocumented) - promise: QueryRefPromise; - // (undocumented) - refetch(variables: OperationVariables | undefined): Promise>; - // (undocumented) - reinitialize(): void; - // (undocumented) - result: ApolloQueryResult; - // (undocumented) - retain(): () => void; - // (undocumented) - softRetain(): () => void; - // (undocumented) - get watchQueryOptions(): WatchQueryOptions; -} - -// @public (undocumented) -interface InternalQueryReferenceOptions { - // (undocumented) - autoDisposeTimeoutMs?: number; - // (undocumented) - onDispose?: () => void; -} - // Warning: (ae-forgotten-export) The symbol "InternalRefetchQueryDescriptor" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RefetchQueriesIncludeShorthand" needs to be exported by the entry point index.d.ts // @@ -1043,9 +980,6 @@ execute: LazyQueryExecFunction, result: QueryResult ]; -// @public (undocumented) -type Listener = (promise: QueryRefPromise) => void; - // @public (undocumented) export type LoadableQueryHookFetchPolicy = Extract; @@ -1379,14 +1313,6 @@ export interface ObservableQueryFields; - // @public (undocumented) export interface OnDataOptions { // (undocumented) @@ -1448,10 +1374,9 @@ export namespace parser { // @public (undocumented) type Path = ReadonlyArray; -// @public (undocumented) -interface PendingPromise extends Promise { - // (undocumented) - status: "pending"; +// @public +export interface PreloadedQueryRef extends QueryRef { + toPromise(): Promise>; } // @public (undocumented) @@ -1460,18 +1385,18 @@ export type PreloadQueryFetchPolicy = Extract>(query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg, TOptions>): QueryReference | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables>; + >(query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg, TOptions>): PreloadedQueryRef | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables>; (query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & { returnPartialData: true; errorPolicy: "ignore" | "all"; - }): QueryReference | undefined, TVariables>; + }): PreloadedQueryRef | undefined, TVariables>; (query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & { errorPolicy: "ignore" | "all"; - }): QueryReference; + }): PreloadedQueryRef; (query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & { returnPartialData: true; - }): QueryReference, TVariables>; - (query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg>): QueryReference; + }): PreloadedQueryRef, TVariables>; + (query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg>): PreloadedQueryRef; } // Warning: (ae-forgotten-export) The symbol "VariablesOption" needs to be exported by the entry point index.d.ts @@ -1499,17 +1424,7 @@ options: PreloadQueryOptions> & Omit = PendingPromise | FulfilledPromise | RejectedPromise; - -// @public (undocumented) -const QUERY_REFERENCE_SYMBOL: unique symbol; +const QUERY_REF_BRAND: unique symbol; // @public (undocumented) interface QueryData { @@ -1598,12 +1513,6 @@ class QueryInfo { variables?: Record; } -// @public (undocumented) -interface QueryKey { - // (undocumented) - __queryKey?: string; -} - // @public @deprecated (undocumented) export interface QueryLazyOptions { context?: Context; @@ -1754,20 +1663,16 @@ interface QueryOptions { } // @public -export interface QueryReference { - // @internal (undocumented) - [PROMISE_SYMBOL]: QueryRefPromise; - // Warning: (ae-forgotten-export) The symbol "InternalQueryReference" needs to be exported by the entry point index.d.ts - // +export interface QueryRef { // @internal (undocumented) - readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - toPromise(): Promise>; + [QUERY_REF_BRAND]?(variables: TVariables): TData; } -// Warning: (ae-forgotten-export) The symbol "PromiseWithState" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type QueryRefPromise = PromiseWithState>; +// @public @deprecated (undocumented) +export interface QueryReference extends QueryRef { + // @deprecated (undocumented) + toPromise?: unknown; +} // @public (undocumented) export interface QueryResult extends ObservableQueryFields { @@ -1874,14 +1779,6 @@ type RefetchQueryDescriptor = string | DocumentNode; // @public (undocumented) type RefetchWritePolicy = "merge" | "overwrite"; -// @public (undocumented) -interface RejectedPromise extends Promise { - // (undocumented) - reason: unknown; - // (undocumented) - status: "rejected"; -} - // @public (undocumented) class RenderPromises { // (undocumented) @@ -2124,7 +2021,7 @@ export function useApolloClient(override?: ApolloClient): ApolloClient, "variables">>(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer & TOptions): [ -(QueryReference | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), +(QueryRef | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), UseBackgroundQueryResult ]; @@ -2133,7 +2030,7 @@ export function useBackgroundQuery | undefined, TVariables>, +QueryRef | undefined, TVariables>, UseBackgroundQueryResult ]; @@ -2141,7 +2038,7 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { errorPolicy: "ignore" | "all"; }): [ -QueryReference, +QueryRef, UseBackgroundQueryResult ]; @@ -2150,7 +2047,7 @@ export function useBackgroundQuery, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; @@ -2158,7 +2055,7 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; }): [ -QueryReference, TVariables>, +QueryRef, TVariables>, UseBackgroundQueryResult ]; @@ -2166,15 +2063,12 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { skip: boolean; }): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; // @public (undocumented) -export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [ -QueryReference, -UseBackgroundQueryResult -]; +export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [QueryRef, UseBackgroundQueryResult]; // @public (undocumented) export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken): [undefined, UseBackgroundQueryResult]; @@ -2183,13 +2077,13 @@ export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken | (BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; })): [ -QueryReference, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; // @public (undocumented) export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: SkipToken | BackgroundQueryHookOptionsNoInfer): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; @@ -2250,7 +2144,7 @@ export function useLoadableQuery = [ loadQuery: LoadQueryFunction, -queryRef: QueryReference | null, +queryRef: QueryRef | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -2265,7 +2159,7 @@ export function useMutation(query: DocumentNode | TypedDocumentNode, options?: QueryHookOptions, NoInfer_2>): QueryResult; // @public -export function useQueryRefHandlers(queryRef: QueryReference): UseQueryRefHandlersResult; +export function useQueryRefHandlers(queryRef: QueryRef): UseQueryRefHandlersResult; // @public (undocumented) export interface UseQueryRefHandlersResult { @@ -2279,7 +2173,7 @@ export interface UseQueryRefHandlersResult(rv: ReactiveVar): T; // @public (undocumented) -export function useReadQuery(queryRef: QueryReference): UseReadQueryResult; +export function useReadQuery(queryRef: QueryRef): UseReadQueryResult; // @public (undocumented) export interface UseReadQueryResult { @@ -2413,7 +2307,7 @@ interface WatchQueryOptions = (fetchMor }) => TData; }) => Promise>; -// @public (undocumented) -type FetchMoreOptions = Parameters["fetchMore"]>[0]; - // @public (undocumented) interface FetchMoreQueryOptions { // (undocumented) @@ -768,14 +765,6 @@ interface FragmentMap { // @public (undocumented) type FragmentMatcher = (rootValue: any, typeCondition: string, context: any) => boolean; -// @public (undocumented) -interface FulfilledPromise extends Promise { - // (undocumented) - status: "fulfilled"; - // (undocumented) - value: TValue; -} - // @internal const getApolloCacheMemoryInternals: (() => { cache: { @@ -860,58 +849,6 @@ interface IncrementalPayload { path: Path; } -// @public (undocumented) -class InternalQueryReference { - // Warning: (ae-forgotten-export) The symbol "InternalQueryReferenceOptions" needs to be exported by the entry point index.d.ts - constructor(observable: ObservableQuery, options: InternalQueryReferenceOptions); - // (undocumented) - applyOptions(watchQueryOptions: ObservedOptions): QueryRefPromise; - // Warning: (ae-forgotten-export) The symbol "ObservedOptions" needs to be exported by the entry point index.d.ts - // - // (undocumented) - didChangeOptions(watchQueryOptions: ObservedOptions): boolean; - // (undocumented) - get disposed(): boolean; - // Warning: (ae-forgotten-export) The symbol "FetchMoreOptions" needs to be exported by the entry point index.d.ts - // - // (undocumented) - fetchMore(options: FetchMoreOptions): Promise>; - // Warning: (ae-forgotten-export) The symbol "QueryKey" needs to be exported by the entry point index.d.ts - // - // (undocumented) - readonly key: QueryKey; - // Warning: (ae-forgotten-export) The symbol "Listener" needs to be exported by the entry point index.d.ts - // - // (undocumented) - listen(listener: Listener): () => void; - // (undocumented) - readonly observable: ObservableQuery; - // Warning: (ae-forgotten-export) The symbol "QueryRefPromise" needs to be exported by the entry point index.d.ts - // - // (undocumented) - promise: QueryRefPromise; - // (undocumented) - refetch(variables: OperationVariables | undefined): Promise>; - // (undocumented) - reinitialize(): void; - // (undocumented) - result: ApolloQueryResult; - // (undocumented) - retain(): () => void; - // (undocumented) - softRetain(): () => void; - // (undocumented) - get watchQueryOptions(): WatchQueryOptions; -} - -// @public (undocumented) -interface InternalQueryReferenceOptions { - // (undocumented) - autoDisposeTimeoutMs?: number; - // (undocumented) - onDispose?: () => void; -} - // Warning: (ae-forgotten-export) The symbol "InternalRefetchQueryDescriptor" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RefetchQueriesIncludeShorthand" needs to be exported by the entry point index.d.ts // @@ -991,9 +928,6 @@ execute: LazyQueryExecFunction, result: QueryResult ]; -// @public (undocumented) -type Listener = (promise: QueryRefPromise) => void; - // @public (undocumented) type LoadableQueryHookFetchPolicy = Extract; @@ -1323,14 +1257,6 @@ interface ObservableQueryFields { variables: TVariables | undefined; } -// @public (undocumented) -const OBSERVED_CHANGED_OPTIONS: readonly ["canonizeResults", "context", "errorPolicy", "fetchPolicy", "refetchWritePolicy", "returnPartialData"]; - -// Warning: (ae-forgotten-export) The symbol "OBSERVED_CHANGED_OPTIONS" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type ObservedOptions = Pick; - // @public (undocumented) interface OnDataOptions { // (undocumented) @@ -1382,27 +1308,11 @@ type OperationVariables = Record; // @public (undocumented) type Path = ReadonlyArray; -// @public (undocumented) -interface PendingPromise extends Promise { - // (undocumented) - status: "pending"; -} - // @public (undocumented) type Primitive = null | undefined | string | number | boolean | symbol | bigint; // @public (undocumented) -const PROMISE_SYMBOL: unique symbol; - -// Warning: (ae-forgotten-export) The symbol "PendingPromise" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "FulfilledPromise" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "RejectedPromise" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type PromiseWithState = PendingPromise | FulfilledPromise | RejectedPromise; - -// @public (undocumented) -const QUERY_REFERENCE_SYMBOL: unique symbol; +const QUERY_REF_BRAND: unique symbol; // @public (undocumented) interface QueryFunctionOptions extends BaseQueryOptions { @@ -1478,12 +1388,6 @@ class QueryInfo { variables?: Record; } -// @public (undocumented) -interface QueryKey { - // (undocumented) - __queryKey?: string; -} - // @public (undocumented) type QueryListener = (queryInfo: QueryInfo) => void; @@ -1628,21 +1532,11 @@ interface QueryOptions { } // @public -interface QueryReference { +interface QueryRef { // @internal (undocumented) - [PROMISE_SYMBOL]: QueryRefPromise; - // Warning: (ae-forgotten-export) The symbol "InternalQueryReference" needs to be exported by the entry point index.d.ts - // - // @internal (undocumented) - readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - toPromise(): Promise>; + [QUERY_REF_BRAND]?(variables: TVariables): TData; } -// Warning: (ae-forgotten-export) The symbol "PromiseWithState" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type QueryRefPromise = PromiseWithState>; - // Warning: (ae-forgotten-export) The symbol "ObservableQueryFields" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -1744,14 +1638,6 @@ type RefetchQueryDescriptor = string | DocumentNode; // @public (undocumented) type RefetchWritePolicy = "merge" | "overwrite"; -// @public (undocumented) -interface RejectedPromise extends Promise { - // (undocumented) - reason: unknown; - // (undocumented) - status: "rejected"; -} - // @public (undocumented) type RequestHandler = (operation: Operation, forward: NextLink) => Observable | null; @@ -1955,11 +1841,11 @@ interface UriFunction { export function useApolloClient(override?: ApolloClient): ApolloClient; // Warning: (ae-forgotten-export) The symbol "BackgroundQueryHookOptionsNoInfer" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "QueryReference" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "QueryRef" needs to be exported by the entry point index.d.ts // // @public (undocumented) export function useBackgroundQuery, "variables">>(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer & TOptions): [ -(QueryReference | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), +(QueryRef | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), UseBackgroundQueryResult ]; @@ -1968,7 +1854,7 @@ export function useBackgroundQuery | undefined, TVariables>, +QueryRef | undefined, TVariables>, UseBackgroundQueryResult ]; @@ -1976,7 +1862,7 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { errorPolicy: "ignore" | "all"; }): [ -QueryReference, +QueryRef, UseBackgroundQueryResult ]; @@ -1985,7 +1871,7 @@ export function useBackgroundQuery, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; @@ -1993,7 +1879,7 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; }): [ -QueryReference, TVariables>, +QueryRef, TVariables>, UseBackgroundQueryResult ]; @@ -2001,15 +1887,12 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { skip: boolean; }): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; // @public (undocumented) -export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [ -QueryReference, -UseBackgroundQueryResult -]; +export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [QueryRef, UseBackgroundQueryResult]; // @public (undocumented) export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken): [undefined, UseBackgroundQueryResult]; @@ -2018,13 +1901,13 @@ export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken | (BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; })): [ -QueryReference, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; // @public (undocumented) export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: SkipToken | BackgroundQueryHookOptionsNoInfer): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; @@ -2089,7 +1972,7 @@ export function useLoadableQuery = [ loadQuery: LoadQueryFunction, -queryRef: QueryReference | null, +queryRef: QueryRef | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -2107,7 +1990,7 @@ export function useMutation(query: DocumentNode | TypedDocumentNode, options?: QueryHookOptions, NoInfer_2>): QueryResult; // @public -export function useQueryRefHandlers(queryRef: QueryReference): UseQueryRefHandlersResult; +export function useQueryRefHandlers(queryRef: QueryRef): UseQueryRefHandlersResult; // @public (undocumented) export interface UseQueryRefHandlersResult { @@ -2121,7 +2004,7 @@ export interface UseQueryRefHandlersResult(rv: ReactiveVar): T; // @public (undocumented) -export function useReadQuery(queryRef: QueryReference): UseReadQueryResult; +export function useReadQuery(queryRef: QueryRef): UseReadQueryResult; // @public (undocumented) export interface UseReadQueryResult { @@ -2248,7 +2131,7 @@ interface WatchQueryOptions { partial?: boolean; } +// Warning: (ae-forgotten-export) The symbol "WrappedQueryRef" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function assertWrappedQueryRef(queryRef: QueryRef): asserts queryRef is WrappedQueryRef; + +// @public (undocumented) +export function assertWrappedQueryRef(queryRef: QueryRef | undefined | null): asserts queryRef is WrappedQueryRef | undefined | null; + // @public type AsStoreObject & { // Warning: (ae-forgotten-export) The symbol "QueryRefPromise" needs to be exported by the entry point index.d.ts // // @public (undocumented) -export function getWrappedPromise(queryRef: QueryReference): QueryRefPromise; +export function getWrappedPromise(queryRef: WrappedQueryRef): QueryRefPromise; // @public (undocumented) type GraphQLErrors = ReadonlyArray; @@ -1274,6 +1282,11 @@ interface PendingPromise extends Promise { status: "pending"; } +// @public +export interface PreloadedQueryRef extends QueryRef { + toPromise(): Promise>; +} + // @public (undocumented) type Primitive = null | undefined | string | number | boolean | symbol | bigint; @@ -1287,6 +1300,9 @@ const PROMISE_SYMBOL: unique symbol; // @public (undocumented) type PromiseWithState = PendingPromise | FulfilledPromise | RejectedPromise; +// @public (undocumented) +const QUERY_REF_BRAND: unique symbol; + // @public (undocumented) const QUERY_REFERENCE_SYMBOL: unique symbol; @@ -1516,12 +1532,15 @@ interface QueryOptions { } // @public -export interface QueryReference { +export interface QueryRef { // @internal (undocumented) - [PROMISE_SYMBOL]: QueryRefPromise; - // @internal (undocumented) - readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - toPromise(): Promise>; + [QUERY_REF_BRAND]?(variables: TVariables): TData; +} + +// @public @deprecated (undocumented) +export interface QueryReference extends QueryRef { + // @deprecated (undocumented) + toPromise?: unknown; } // Warning: (ae-forgotten-export) The symbol "PromiseWithState" needs to be exported by the entry point index.d.ts @@ -1804,7 +1823,10 @@ type UnionForAny = T extends never ? "a" : 1; type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; // @public (undocumented) -export function unwrapQueryRef(queryRef: QueryReference): InternalQueryReference; +export function unwrapQueryRef(queryRef: WrappedQueryRef): InternalQueryReference; + +// @public (undocumented) +export function unwrapQueryRef(queryRef: Partial>): undefined | InternalQueryReference; // @public (undocumented) type UpdateQueries = MutationOptions["updateQueries"]; @@ -1818,7 +1840,7 @@ type UpdateQueryFn TData; // @public (undocumented) -export function updateWrappedQueryRef(queryRef: QueryReference, promise: QueryRefPromise): void; +export function updateWrappedQueryRef(queryRef: WrappedQueryRef, promise: QueryRefPromise): void; // @public (undocumented) interface UriFunction { @@ -1831,7 +1853,7 @@ interface UriFunction { // // @public (undocumented) function useBackgroundQuery, "variables">>(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer & TOptions): [ -(QueryReference | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), +(QueryRef | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), UseBackgroundQueryResult ]; @@ -1840,7 +1862,7 @@ function useBackgroundQuery | undefined, TVariables>, +QueryRef | undefined, TVariables>, UseBackgroundQueryResult ]; @@ -1848,7 +1870,7 @@ UseBackgroundQueryResult function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { errorPolicy: "ignore" | "all"; }): [ -QueryReference, +QueryRef, UseBackgroundQueryResult ]; @@ -1857,7 +1879,7 @@ function useBackgroundQuery, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; @@ -1865,7 +1887,7 @@ UseBackgroundQueryResult function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; }): [ -QueryReference, TVariables>, +QueryRef, TVariables>, UseBackgroundQueryResult ]; @@ -1873,15 +1895,12 @@ UseBackgroundQueryResult function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { skip: boolean; }): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; // @public (undocumented) -function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [ -QueryReference, -UseBackgroundQueryResult -]; +function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [QueryRef, UseBackgroundQueryResult]; // Warning: (ae-forgotten-export) The symbol "SkipToken" needs to be exported by the entry point index.d.ts // @@ -1892,13 +1911,13 @@ function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken | (BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; })): [ -QueryReference, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; // @public (undocumented) function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: SkipToken | BackgroundQueryHookOptionsNoInfer): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; @@ -1942,7 +1961,7 @@ function useQuery(queryRef: QueryReference): UseQueryRefHandlersResult; +function useQueryRefHandlers(queryRef: QueryRef): UseQueryRefHandlersResult; // @public (undocumented) interface UseQueryRefHandlersResult { @@ -1953,7 +1972,7 @@ interface UseQueryRefHandlersResult(queryRef: QueryReference): UseReadQueryResult; +function useReadQuery(queryRef: QueryRef): UseReadQueryResult; // @public (undocumented) interface UseReadQueryResult { @@ -2084,8 +2103,18 @@ interface WrappableHooks { useSuspenseQuery: typeof useSuspenseQuery; } +// @internal +interface WrappedQueryRef extends QueryRef { + // (undocumented) + [PROMISE_SYMBOL]: QueryRefPromise; + // (undocumented) + readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; + // (undocumented) + toPromise?(): Promise; +} + // @public (undocumented) -export function wrapQueryRef(internalQueryRef: InternalQueryReference): QueryReference; +export function wrapQueryRef(internalQueryRef: InternalQueryReference): WrappedQueryRef; // Warnings were encountered during analysis: // diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index a0175f71a52..632f1f0976d 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -915,9 +915,6 @@ export interface FetchMoreOptions }) => TData; } -// @public (undocumented) -type FetchMoreOptions_2 = Parameters["fetchMore"]>[0]; - // @public (undocumented) export interface FetchMoreQueryOptions { // (undocumented) @@ -1034,14 +1031,6 @@ export function fromError(errorValue: any): Observable; // @public (undocumented) export function fromPromise(promise: Promise): Observable; -// @public (undocumented) -interface FulfilledPromise extends Promise { - // (undocumented) - status: "fulfilled"; - // (undocumented) - value: TValue; -} - // @internal const getApolloCacheMemoryInternals: (() => { cache: { @@ -1291,58 +1280,6 @@ export interface InMemoryCacheConfig extends ApolloReducerConfig { typePolicies?: TypePolicies; } -// @public (undocumented) -class InternalQueryReference { - // Warning: (ae-forgotten-export) The symbol "InternalQueryReferenceOptions" needs to be exported by the entry point index.d.ts - constructor(observable: ObservableQuery, options: InternalQueryReferenceOptions); - // (undocumented) - applyOptions(watchQueryOptions: ObservedOptions): QueryRefPromise; - // Warning: (ae-forgotten-export) The symbol "ObservedOptions" needs to be exported by the entry point index.d.ts - // - // (undocumented) - didChangeOptions(watchQueryOptions: ObservedOptions): boolean; - // (undocumented) - get disposed(): boolean; - // Warning: (ae-forgotten-export) The symbol "FetchMoreOptions_2" needs to be exported by the entry point index.d.ts - // - // (undocumented) - fetchMore(options: FetchMoreOptions_2): Promise>; - // Warning: (ae-forgotten-export) The symbol "QueryKey" needs to be exported by the entry point index.d.ts - // - // (undocumented) - readonly key: QueryKey; - // Warning: (ae-forgotten-export) The symbol "Listener" needs to be exported by the entry point index.d.ts - // - // (undocumented) - listen(listener: Listener): () => void; - // (undocumented) - readonly observable: ObservableQuery; - // Warning: (ae-forgotten-export) The symbol "QueryRefPromise" needs to be exported by the entry point index.d.ts - // - // (undocumented) - promise: QueryRefPromise; - // (undocumented) - refetch(variables: OperationVariables | undefined): Promise>; - // (undocumented) - reinitialize(): void; - // (undocumented) - result: ApolloQueryResult; - // (undocumented) - retain(): () => void; - // (undocumented) - softRetain(): () => void; - // (undocumented) - get watchQueryOptions(): WatchQueryOptions; -} - -// @public (undocumented) -interface InternalQueryReferenceOptions { - // (undocumented) - autoDisposeTimeoutMs?: number; - // (undocumented) - onDispose?: () => void; -} - // Warning: (ae-forgotten-export) The symbol "RefetchQueriesIncludeShorthand" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -1462,9 +1399,6 @@ execute: LazyQueryExecFunction, result: QueryResult ]; -// @public (undocumented) -type Listener = (promise: QueryRefPromise) => void; - // @public (undocumented) export type LoadableQueryHookFetchPolicy = Extract; @@ -1880,14 +1814,6 @@ export interface ObservableQueryFields; - export { Observer } // @public (undocumented) @@ -1964,12 +1890,6 @@ export namespace parser { // @public (undocumented) export type Path = ReadonlyArray; -// @public (undocumented) -interface PendingPromise extends Promise { - // (undocumented) - status: "pending"; -} - // @public (undocumented) class Policies { constructor(config: { @@ -2017,24 +1937,29 @@ export type PossibleTypesMap = { [supertype: string]: string[]; }; +// @public +export interface PreloadedQueryRef extends QueryRef { + toPromise(): Promise>; +} + // @public (undocumented) export type PreloadQueryFetchPolicy = Extract; // @public export interface PreloadQueryFunction { // Warning: (ae-forgotten-export) The symbol "PreloadQueryOptionsArg" needs to be exported by the entry point index.d.ts - >(query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg, TOptions>): QueryReference | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables>; + >(query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg, TOptions>): PreloadedQueryRef | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables>; (query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & { returnPartialData: true; errorPolicy: "ignore" | "all"; - }): QueryReference | undefined, TVariables>; + }): PreloadedQueryRef | undefined, TVariables>; (query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & { errorPolicy: "ignore" | "all"; - }): QueryReference; + }): PreloadedQueryRef; (query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & { returnPartialData: true; - }): QueryReference, TVariables>; - (query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg>): QueryReference; + }): PreloadedQueryRef, TVariables>; + (query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg>): PreloadedQueryRef; } // Warning: (ae-forgotten-export) The symbol "VariablesOption" needs to be exported by the entry point index.d.ts @@ -2075,17 +2000,7 @@ interface Printer { } // @public (undocumented) -const PROMISE_SYMBOL: unique symbol; - -// Warning: (ae-forgotten-export) The symbol "PendingPromise" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "FulfilledPromise" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "RejectedPromise" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type PromiseWithState = PendingPromise | FulfilledPromise | RejectedPromise; - -// @public (undocumented) -const QUERY_REFERENCE_SYMBOL: unique symbol; +const QUERY_REF_BRAND: unique symbol; // @public (undocumented) interface QueryData { @@ -2172,12 +2087,6 @@ class QueryInfo { variables?: Record; } -// @public (undocumented) -interface QueryKey { - // (undocumented) - __queryKey?: string; -} - // @public @deprecated (undocumented) export interface QueryLazyOptions { context?: DefaultContext; @@ -2325,20 +2234,16 @@ export { QueryOptions as PureQueryOptions } export { QueryOptions } // @public -export interface QueryReference { - // @internal (undocumented) - [PROMISE_SYMBOL]: QueryRefPromise; - // Warning: (ae-forgotten-export) The symbol "InternalQueryReference" needs to be exported by the entry point index.d.ts - // +export interface QueryRef { // @internal (undocumented) - readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; - toPromise(): Promise>; + [QUERY_REF_BRAND]?(variables: TVariables): TData; } -// Warning: (ae-forgotten-export) The symbol "PromiseWithState" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type QueryRefPromise = PromiseWithState>; +// @public @deprecated (undocumented) +export interface QueryReference extends QueryRef { + // @deprecated (undocumented) + toPromise?: unknown; +} // @public (undocumented) export interface QueryResult extends ObservableQueryFields { @@ -2459,14 +2364,6 @@ export type RefetchQueryDescriptor = string | DocumentNode; // @public (undocumented) export type RefetchWritePolicy = "merge" | "overwrite"; -// @public (undocumented) -interface RejectedPromise extends Promise { - // (undocumented) - reason: unknown; - // (undocumented) - status: "rejected"; -} - // @public (undocumented) class RenderPromises { // (undocumented) @@ -2787,7 +2684,7 @@ export function useApolloClient(override?: ApolloClient): ApolloClient, "variables">>(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer & TOptions): [ -(QueryReference | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), +(QueryRef | undefined : TData | undefined : TOptions["returnPartialData"] extends true ? DeepPartial : TData, TVariables> | (TOptions["skip"] extends boolean ? undefined : never)), UseBackgroundQueryResult ]; @@ -2796,7 +2693,7 @@ export function useBackgroundQuery | undefined, TVariables>, +QueryRef | undefined, TVariables>, UseBackgroundQueryResult ]; @@ -2804,7 +2701,7 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { errorPolicy: "ignore" | "all"; }): [ -QueryReference, +QueryRef, UseBackgroundQueryResult ]; @@ -2813,7 +2710,7 @@ export function useBackgroundQuery, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; @@ -2821,7 +2718,7 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; }): [ -QueryReference, TVariables>, +QueryRef, TVariables>, UseBackgroundQueryResult ]; @@ -2829,15 +2726,12 @@ UseBackgroundQueryResult export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: BackgroundQueryHookOptionsNoInfer & { skip: boolean; }): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; // @public (undocumented) -export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [ -QueryReference, -UseBackgroundQueryResult -]; +export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer): [QueryRef, UseBackgroundQueryResult]; // @public (undocumented) export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken): [undefined, UseBackgroundQueryResult]; @@ -2846,13 +2740,13 @@ export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options: SkipToken | (BackgroundQueryHookOptionsNoInfer & { returnPartialData: true; })): [ -QueryReference, TVariables> | undefined, +QueryRef, TVariables> | undefined, UseBackgroundQueryResult ]; // @public (undocumented) export function useBackgroundQuery(query: DocumentNode | TypedDocumentNode, options?: SkipToken | BackgroundQueryHookOptionsNoInfer): [ -QueryReference | undefined, +QueryRef | undefined, UseBackgroundQueryResult ]; @@ -2913,7 +2807,7 @@ export function useLoadableQuery = [ loadQuery: LoadQueryFunction, -queryRef: QueryReference | null, +queryRef: QueryRef | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -2928,7 +2822,7 @@ export function useMutation(query: DocumentNode | TypedDocumentNode, options?: QueryHookOptions, NoInfer_2>): QueryResult; // @public -export function useQueryRefHandlers(queryRef: QueryReference): UseQueryRefHandlersResult; +export function useQueryRefHandlers(queryRef: QueryRef): UseQueryRefHandlersResult; // @public (undocumented) export interface UseQueryRefHandlersResult { @@ -2940,7 +2834,7 @@ export interface UseQueryRefHandlersResult(rv: ReactiveVar): T; // @public (undocumented) -export function useReadQuery(queryRef: QueryReference): UseReadQueryResult; +export function useReadQuery(queryRef: QueryRef): UseReadQueryResult; // @public (undocumented) export interface UseReadQueryResult { @@ -3102,7 +2996,7 @@ interface WriteContext extends ReadMergeModifyContext { // src/link/http/selectHttpOptionsAndBody.ts:128:32 - (ae-forgotten-export) The symbol "HttpQueryOptions" needs to be exported by the entry point index.d.ts // src/react/hooks/useBackgroundQuery.ts:29:3 - (ae-forgotten-export) The symbol "FetchMoreFunction" needs to be exported by the entry point index.d.ts // src/react/hooks/useBackgroundQuery.ts:30:3 - (ae-forgotten-export) The symbol "RefetchFunction" needs to be exported by the entry point index.d.ts -// src/react/hooks/useLoadableQuery.ts:106:1 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts +// src/react/hooks/useLoadableQuery.ts:107:1 - (ae-forgotten-export) The symbol "ResetFunction" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/.changeset/late-planets-argue.md b/.changeset/late-planets-argue.md new file mode 100644 index 00000000000..a48a4898545 --- /dev/null +++ b/.changeset/late-planets-argue.md @@ -0,0 +1,23 @@ +--- +"@apollo/client": patch +--- + +Create branded `QueryRef` type without exposed properties. + +This change deprecates `QueryReference` in favor of a `QueryRef` type that doesn't expose any properties. +This change also updates `preloadQuery` to return a new `PreloadedQueryRef` type, which exposes the `toPromise` function as it does today. This means that query refs produced by `useBackgroundQuery` and `useLoadableQuery` now return `QueryRef` types that do not have access to a `toPromise` function, which was never meant to be used in combination with these hooks. + +While we tend to avoid any types of breaking changes in patch releases as this, this change was necessary to support an upcoming version of the React Server Component integration, which needed to omit the `toPromise` function that would otherwise have broken at runtime. +Note that this is a TypeScript-only change. At runtime, `toPromise` is still present on all queryRefs currently created by this package - but we strongly want to discourage you from accessing it in all cases except for the `PreloadedQueryRef` use case. + +Migration is as simple as replacing all references to `QueryReference` with `QueryRef`, so it should be possible to do this with a search & replace in most code bases: + +```diff +-import { QueryReference } from '@apollo/client' ++import { QueryRef } from '@apollo/client' + +- function Component({ queryRef }: { queryRef: QueryReference }) { ++ function Component({ queryRef }: { queryRef: QueryRef }) { + // ... +} +``` diff --git a/.circleci/config.yml b/.circleci/config.yml index c9263ab3d15..2af786f797e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -75,6 +75,9 @@ jobs: - attach_workspace: at: /tmp/workspace - run: npm version + - run: + command: npm pkg set "overrides[@apollo/client]=/tmp/workspace/apollo-client.tgz" + working_directory: integration-tests - run: command: | export VERSION=$(npm show react --json | jq '."dist-tags"."<< parameters.react >>"' -r) @@ -84,7 +87,7 @@ jobs: command: npm run ci-preparations --workspace=<< parameters.framework >> --if-present working_directory: integration-tests - run: - command: npm install @apollo/client@/tmp/workspace/apollo-client.tgz --workspace=<< parameters.framework >> + command: npm install working_directory: integration-tests - run: command: npx playwright install-deps diff --git a/.size-limits.json b/.size-limits.json index 855bf336313..7be0182bcaf 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { - "dist/apollo-client.min.cjs": 39540, - "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32826 + "dist/apollo-client.min.cjs": 39577, + "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32827 } diff --git a/config/inlineInheritDoc.ts b/config/inlineInheritDoc.ts index 0bb126629ae..558be9f375f 100644 --- a/config/inlineInheritDoc.ts +++ b/config/inlineInheritDoc.ts @@ -144,7 +144,8 @@ function processComments() { Node.isPropertySignature(node) || Node.isMethodSignature(node) || Node.isMethodDeclaration(node) || - Node.isCallSignatureDeclaration(node) + Node.isCallSignatureDeclaration(node) || + Node.isInterfaceDeclaration(node) ) { const docsNode = node.getJsDocs()[0]; if (!docsNode) return; diff --git a/docs/shared/Overrides/UseLoadableQueryResult.js b/docs/shared/Overrides/UseLoadableQueryResult.js index 19a4d345d44..78c45ced062 100644 --- a/docs/shared/Overrides/UseLoadableQueryResult.js +++ b/docs/shared/Overrides/UseLoadableQueryResult.js @@ -10,7 +10,7 @@ const HANDLERS = `{ const RETURN_VALUE = `[ loadQuery: LoadQueryFunction, - queryRef: QueryReference | null, + queryRef: QueryRef | null, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -38,10 +38,10 @@ export function UseLoadableQueryResult() { }, { name: "queryRef", - type: "QueryReference | null", + type: "QueryRef | null", description: "The `queryRef` used by `useReadQuery` to read the query result.", - canonicalReference: "@apollo/client!QueryReference:interface", + canonicalReference: "@apollo/client!QueryRef:interface", }, { name: "handlers", diff --git a/docs/shared/useBackgroundQuery-result.mdx b/docs/shared/useBackgroundQuery-result.mdx index 4abe01ef38e..529ce5e0b59 100644 --- a/docs/shared/useBackgroundQuery-result.mdx +++ b/docs/shared/useBackgroundQuery-result.mdx @@ -22,7 +22,7 @@ ###### `queryRef` -`QueryReference` +`QueryRef` diff --git a/docs/source/api/react/hooks.mdx b/docs/source/api/react/hooks.mdx index 80ef1dc3710..22358afd152 100644 --- a/docs/source/api/react/hooks.mdx +++ b/docs/source/api/react/hooks.mdx @@ -343,7 +343,7 @@ function useBackgroundQuery( ): [ // Will return `undefined` here if no query has been executed yet and the query // is currently skipped using `skipToken` or { skip: true } - QueryReference | undefined, + QueryRef | undefined, { fetchMore: FetchMoreFunction; refetch: RefetchFunction; @@ -388,7 +388,7 @@ See the [example](#example-10) in the `useBackgroundQuery` section above. ```ts function useReadQuery( - queryRef: QueryReference + queryRef: QueryRef ): { data: TData; networkStatus: NetworkStatus; @@ -402,7 +402,7 @@ function useReadQuery( | Param | Type | Description | | ------- | ------------ | ------------------------------------------------------------- | -| `queryRef` | QueryReference | The [`queryRef`](#queryref) that was generated via `useBackgroundQuery`. | +| `queryRef` | QueryRef | The [`queryRef`](#queryref) that was generated via `useBackgroundQuery`. | ### Result diff --git a/docs/source/data/suspense.mdx b/docs/source/data/suspense.mdx index d34e7bfc232..793d5eb3c2c 100644 --- a/docs/source/data/suspense.mdx +++ b/docs/source/data/suspense.mdx @@ -437,7 +437,7 @@ function Dog({ id, queryRef }: DogProps) { } interface BreedsProps { - queryRef: QueryReference; + queryRef: QueryRef; } function Breeds({ queryRef }: BreedsProps) { @@ -691,7 +691,7 @@ import { useReadQuery, gql, TypedDocumentNode, - QueryReference, + QueryRef, } from "@apollo/client"; function App() { diff --git a/integration-tests/next/package.json b/integration-tests/next/package.json index fc386463424..5272499fc27 100644 --- a/integration-tests/next/package.json +++ b/integration-tests/next/package.json @@ -7,7 +7,7 @@ "build": "next build", "start": "next start", "serve-app": "npm run start", - "ci-preparations": "npm install @apollo/experimental-nextjs-app-support", + "ci-preparations": "npm install --legacy-peer-deps @apollo/experimental-nextjs-app-support", "test": "playwright test" }, "dependencies": { diff --git a/integration-tests/next/src/app/cc/ApolloWrapper.tsx b/integration-tests/next/src/app/cc/ApolloWrapper.tsx index 08e92151d85..0b6d14ea8ff 100644 --- a/integration-tests/next/src/app/cc/ApolloWrapper.tsx +++ b/integration-tests/next/src/app/cc/ApolloWrapper.tsx @@ -1,6 +1,6 @@ "use client"; import * as React from "react"; -import { HttpLink } from "@apollo/client"; +import { ApolloLink, HttpLink } from "@apollo/client"; import { ApolloNextAppProvider, NextSSRInMemoryCache, @@ -31,7 +31,10 @@ export function ApolloWrapper({ children }: React.PropsWithChildren<{}>) { return new NextSSRApolloClient({ cache: new NextSSRInMemoryCache(), - link: typeof window === "undefined" ? schemaLink : httpLink, + link: + typeof window === "undefined" ? + (schemaLink as ApolloLink) + : (httpLink as ApolloLink), }); } } diff --git a/integration-tests/next/src/libs/apolloClient.ts b/integration-tests/next/src/libs/apolloClient.ts index d7010d0cfab..ac47b293b57 100644 --- a/integration-tests/next/src/libs/apolloClient.ts +++ b/integration-tests/next/src/libs/apolloClient.ts @@ -48,7 +48,9 @@ function createApolloClient() { link: from([ errorLink, delayLink, - typeof window === "undefined" ? schemaLink : httpLink, + typeof window === "undefined" ? + (schemaLink as ApolloLink) + : (httpLink as ApolloLink), ]), cache: new InMemoryCache(), }); diff --git a/src/__tests__/__snapshots__/exports.ts.snap b/src/__tests__/__snapshots__/exports.ts.snap index f5a1dfd86bc..d3ce1568654 100644 --- a/src/__tests__/__snapshots__/exports.ts.snap +++ b/src/__tests__/__snapshots__/exports.ts.snap @@ -337,6 +337,7 @@ Array [ exports[`exports of public entry points @apollo/client/react/internal 1`] = ` Array [ "InternalQueryReference", + "assertWrappedQueryRef", "getSuspenseCache", "getWrappedPromise", "unwrapQueryRef", diff --git a/src/react/hooks/__tests__/useBackgroundQuery.test.tsx b/src/react/hooks/__tests__/useBackgroundQuery.test.tsx index 36fa009ba73..91d142a4df5 100644 --- a/src/react/hooks/__tests__/useBackgroundQuery.test.tsx +++ b/src/react/hooks/__tests__/useBackgroundQuery.test.tsx @@ -33,7 +33,7 @@ import { import { useBackgroundQuery } from "../useBackgroundQuery"; import { UseReadQueryResult, useReadQuery } from "../useReadQuery"; import { ApolloProvider } from "../../context"; -import { QueryReference } from "../../internal"; +import { QueryRef, QueryReference } from "../../internal"; import { InMemoryCache } from "../../../cache"; import { SuspenseQueryHookFetchPolicy } from "../../types/types"; import equal from "@wry/equality"; @@ -70,7 +70,7 @@ function createDefaultTrackedComponents< return
Loading
; } - function ReadQueryHook({ queryRef }: { queryRef: QueryReference }) { + function ReadQueryHook({ queryRef }: { queryRef: QueryRef }) { useTrackRenders(); Profiler.mergeSnapshot({ result: useReadQuery(queryRef), @@ -557,7 +557,7 @@ it("does not recreate queryRef or execute a network request when rerendering use const Profiler = createProfiler({ initialSnapshot: { - queryRef: null as QueryReference | null, + queryRef: null as QueryRef | null, result: null as UseReadQueryResult | null, }, }); @@ -4843,7 +4843,7 @@ describe("refetch", () => { ); } - function Todo({ queryRef }: { queryRef: QueryReference }) { + function Todo({ queryRef }: { queryRef: QueryRef }) { useTrackRenders(); Profiler.mergeSnapshot({ result: useReadQuery(queryRef) }); @@ -4973,7 +4973,7 @@ describe("refetch", () => { ); } - function Todo({ queryRef }: { queryRef: QueryReference }) { + function Todo({ queryRef }: { queryRef: QueryRef }) { useTrackRenders(); Profiler.mergeSnapshot({ result: useReadQuery(queryRef) }); @@ -6337,7 +6337,7 @@ describe.skip("type tests", () => { expectTypeOf(explicit).not.toEqualTypeOf(); }); - it("returns QueryReference | undefined when `skip` is present", () => { + it("returns QueryRef | undefined when `skip` is present", () => { const { query } = setupVariablesCase(); const [inferredQueryRef] = useBackgroundQuery(query, { @@ -6345,10 +6345,13 @@ describe.skip("type tests", () => { }); expectTypeOf(inferredQueryRef).toEqualTypeOf< + QueryRef | undefined + >(); + expectTypeOf(inferredQueryRef).toMatchTypeOf< QueryReference | undefined >(); expectTypeOf(inferredQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); const [explicitQueryRef] = useBackgroundQuery< @@ -6357,10 +6360,13 @@ describe.skip("type tests", () => { >(query, { skip: true }); expectTypeOf(explicitQueryRef).toEqualTypeOf< + QueryRef | undefined + >(); + expectTypeOf(explicitQueryRef).toMatchTypeOf< QueryReference | undefined >(); expectTypeOf(explicitQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); // TypeScript is too smart and using a `const` or `let` boolean variable @@ -6375,10 +6381,13 @@ describe.skip("type tests", () => { }); expectTypeOf(dynamicQueryRef).toEqualTypeOf< + QueryRef | undefined + >(); + expectTypeOf(dynamicQueryRef).toMatchTypeOf< QueryReference | undefined >(); expectTypeOf(dynamicQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); }); @@ -6389,7 +6398,7 @@ describe.skip("type tests", () => { expectTypeOf(inferredQueryRef).toEqualTypeOf(); expectTypeOf(inferredQueryRef).not.toEqualTypeOf< - QueryReference | undefined + QueryRef | undefined >(); const [explicitQueryRef] = useBackgroundQuery< @@ -6399,11 +6408,11 @@ describe.skip("type tests", () => { expectTypeOf(explicitQueryRef).toEqualTypeOf(); expectTypeOf(explicitQueryRef).not.toEqualTypeOf< - QueryReference | undefined + QueryRef | undefined >(); }); - it("returns QueryReference | undefined when using conditional `skipToken`", () => { + it("returns QueryRef | undefined when using conditional `skipToken`", () => { const { query } = setupVariablesCase(); const options = { skip: true, @@ -6415,10 +6424,13 @@ describe.skip("type tests", () => { ); expectTypeOf(inferredQueryRef).toEqualTypeOf< + QueryRef | undefined + >(); + expectTypeOf(inferredQueryRef).toMatchTypeOf< QueryReference | undefined >(); expectTypeOf(inferredQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); const [explicitQueryRef] = useBackgroundQuery< @@ -6427,14 +6439,17 @@ describe.skip("type tests", () => { >(query, options.skip ? skipToken : undefined); expectTypeOf(explicitQueryRef).toEqualTypeOf< + QueryRef | undefined + >(); + expectTypeOf(explicitQueryRef).toMatchTypeOf< QueryReference | undefined >(); expectTypeOf(explicitQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); }); - it("returns QueryReference> | undefined when using `skipToken` with `returnPartialData`", () => { + it("returns QueryRef> | undefined when using `skipToken` with `returnPartialData`", () => { const { query } = setupVariablesCase(); const options = { skip: true, @@ -6446,11 +6461,15 @@ describe.skip("type tests", () => { ); expectTypeOf(inferredQueryRef).toEqualTypeOf< + | QueryRef, VariablesCaseVariables> + | undefined + >(); + expectTypeOf(inferredQueryRef).toMatchTypeOf< | QueryReference, VariablesCaseVariables> | undefined >(); expectTypeOf(inferredQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); const [explicitQueryRef] = useBackgroundQuery< @@ -6459,11 +6478,15 @@ describe.skip("type tests", () => { >(query, options.skip ? skipToken : { returnPartialData: true }); expectTypeOf(explicitQueryRef).toEqualTypeOf< + | QueryRef, VariablesCaseVariables> + | undefined + >(); + expectTypeOf(explicitQueryRef).toMatchTypeOf< | QueryReference, VariablesCaseVariables> | undefined >(); expectTypeOf(explicitQueryRef).not.toEqualTypeOf< - QueryReference + QueryRef >(); }); }); diff --git a/src/react/hooks/__tests__/useLoadableQuery.test.tsx b/src/react/hooks/__tests__/useLoadableQuery.test.tsx index 4001dea7bd6..520ec1edf98 100644 --- a/src/react/hooks/__tests__/useLoadableQuery.test.tsx +++ b/src/react/hooks/__tests__/useLoadableQuery.test.tsx @@ -42,7 +42,7 @@ import { useReadQuery } from "../useReadQuery"; import { ApolloProvider } from "../../context"; import { InMemoryCache } from "../../../cache"; import { LoadableQueryHookFetchPolicy } from "../../types/types"; -import { QueryReference } from "../../../react"; +import { QueryRef } from "../../../react"; import { FetchMoreFunction, RefetchFunction } from "../useSuspenseQuery"; import invariant, { InvariantError } from "ts-invariant"; import { @@ -183,7 +183,7 @@ function createDefaultProfiledComponents< return

Loading

; } - function ReadQueryHook({ queryRef }: { queryRef: QueryReference }) { + function ReadQueryHook({ queryRef }: { queryRef: QueryRef }) { useTrackRenders(); profiler.mergeSnapshot({ result: useReadQuery(queryRef), @@ -1507,7 +1507,7 @@ it("works with startTransition to change variables", async () => { queryRef, onChange, }: { - queryRef: QueryReference; + queryRef: QueryRef; onChange: (id: string) => void; }) { const { data } = useReadQuery(queryRef); @@ -3143,7 +3143,7 @@ it("`refetch` works with startTransition to allow React to show stale UI until f refetch, }: { refetch: RefetchFunction; - queryRef: QueryReference; + queryRef: QueryRef; onChange: (id: string) => void; }) { const { data } = useReadQuery(queryRef); @@ -3559,7 +3559,7 @@ it("`fetchMore` works with startTransition to allow React to show stale UI until fetchMore, }: { fetchMore: FetchMoreFunction; - queryRef: QueryReference; + queryRef: QueryRef; }) { const { data } = useReadQuery(queryRef); const [isPending, startTransition] = React.useTransition(); diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 072c3c9e5cb..a176f88903a 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4465,7 +4465,7 @@ describe("useQuery Hook", () => { primes: [13, 17, 19, 23, 29], }, }, - delay: 10, + delay: 25, }, ]; diff --git a/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx b/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx index a81c64d8373..012f7fb1872 100644 --- a/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx +++ b/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx @@ -22,7 +22,7 @@ import { UseReadQueryResult, useReadQuery } from "../useReadQuery"; import { Suspense } from "react"; import { createQueryPreloader } from "../../query-preloader/createQueryPreloader"; import userEvent from "@testing-library/user-event"; -import { QueryReference } from "../../internal"; +import { QueryRef } from "../../internal"; import { useBackgroundQuery } from "../useBackgroundQuery"; import { useLoadableQuery } from "../useLoadableQuery"; import { concatPagination } from "../../../utilities"; @@ -770,11 +770,7 @@ test("`refetch` works with startTransition from useBackgroundQuery and usePreloa return

Loading

; } - function ReadQueryHook({ - queryRef, - }: { - queryRef: QueryReference; - }) { + function ReadQueryHook({ queryRef }: { queryRef: QueryRef }) { useTrackRenders(); const [isPending, startTransition] = React.useTransition(); const { refetch } = useQueryRefHandlers(queryRef); @@ -937,11 +933,7 @@ test("refetches from queryRefs produced by useBackgroundQuery", async () => { return

Loading

; } - function ReadQueryHook({ - queryRef, - }: { - queryRef: QueryReference; - }) { + function ReadQueryHook({ queryRef }: { queryRef: QueryRef }) { const { refetch } = useQueryRefHandlers(queryRef); Profiler.mergeSnapshot({ result: useReadQuery(queryRef) }); @@ -1028,11 +1020,7 @@ test("refetches from queryRefs produced by useLoadableQuery", async () => { return

Loading

; } - function ReadQueryHook({ - queryRef, - }: { - queryRef: QueryReference; - }) { + function ReadQueryHook({ queryRef }: { queryRef: QueryRef }) { const { refetch } = useQueryRefHandlers(queryRef); Profiler.mergeSnapshot({ result: useReadQuery(queryRef) }); @@ -1435,7 +1423,7 @@ test("paginates from queryRefs produced by useBackgroundQuery", async () => { function ReadQueryHook({ queryRef, }: { - queryRef: QueryReference; + queryRef: QueryRef; }) { useTrackRenders(); const { fetchMore } = useQueryRefHandlers(queryRef); @@ -1538,7 +1526,7 @@ test("paginates from queryRefs produced by useLoadableQuery", async () => { function ReadQueryHook({ queryRef, }: { - queryRef: QueryReference; + queryRef: QueryRef; }) { useTrackRenders(); const { fetchMore } = useQueryRefHandlers(queryRef); @@ -1781,7 +1769,7 @@ test("`fetchMore` works with startTransition from useBackgroundQuery and useQuer function ReadQueryHook({ queryRef, }: { - queryRef: QueryReference; + queryRef: QueryRef; }) { useTrackRenders(); const [isPending, startTransition] = React.useTransition(); diff --git a/src/react/hooks/useBackgroundQuery.ts b/src/react/hooks/useBackgroundQuery.ts index 601273ce627..4b5a5668389 100644 --- a/src/react/hooks/useBackgroundQuery.ts +++ b/src/react/hooks/useBackgroundQuery.ts @@ -13,7 +13,7 @@ import { updateWrappedQueryRef, wrapQueryRef, } from "../internal/index.js"; -import type { CacheKey, QueryReference } from "../internal/index.js"; +import type { CacheKey, QueryRef } from "../internal/index.js"; import type { BackgroundQueryHookOptions, NoInfer } from "../types/types.js"; import { wrapHook } from "./internal/index.js"; import { useWatchQueryOptions } from "./useSuspenseQuery.js"; @@ -44,7 +44,7 @@ export function useBackgroundQuery< options?: BackgroundQueryHookOptionsNoInfer & TOptions ): [ ( - | QueryReference< + | QueryRef< TOptions["errorPolicy"] extends "ignore" | "all" ? TOptions["returnPartialData"] extends true ? DeepPartial | undefined @@ -68,7 +68,7 @@ export function useBackgroundQuery< errorPolicy: "ignore" | "all"; } ): [ - QueryReference | undefined, TVariables>, + QueryRef | undefined, TVariables>, UseBackgroundQueryResult, ]; @@ -81,7 +81,7 @@ export function useBackgroundQuery< errorPolicy: "ignore" | "all"; } ): [ - QueryReference, + QueryRef, UseBackgroundQueryResult, ]; @@ -95,7 +95,7 @@ export function useBackgroundQuery< returnPartialData: true; } ): [ - QueryReference, TVariables> | undefined, + QueryRef, TVariables> | undefined, UseBackgroundQueryResult, ]; @@ -108,7 +108,7 @@ export function useBackgroundQuery< returnPartialData: true; } ): [ - QueryReference, TVariables>, + QueryRef, TVariables>, UseBackgroundQueryResult, ]; @@ -121,7 +121,7 @@ export function useBackgroundQuery< skip: boolean; } ): [ - QueryReference | undefined, + QueryRef | undefined, UseBackgroundQueryResult, ]; @@ -131,10 +131,7 @@ export function useBackgroundQuery< >( query: DocumentNode | TypedDocumentNode, options?: BackgroundQueryHookOptionsNoInfer -): [ - QueryReference, - UseBackgroundQueryResult, -]; +): [QueryRef, UseBackgroundQueryResult]; export function useBackgroundQuery< TData = unknown, @@ -155,7 +152,7 @@ export function useBackgroundQuery< returnPartialData: true; }) ): [ - QueryReference, TVariables> | undefined, + QueryRef, TVariables> | undefined, UseBackgroundQueryResult, ]; @@ -166,7 +163,7 @@ export function useBackgroundQuery< query: DocumentNode | TypedDocumentNode, options?: SkipToken | BackgroundQueryHookOptionsNoInfer ): [ - QueryReference | undefined, + QueryRef | undefined, UseBackgroundQueryResult, ]; @@ -180,7 +177,7 @@ export function useBackgroundQuery< Partial>) | BackgroundQueryHookOptionsNoInfer = Object.create(null) ): [ - QueryReference | undefined, + QueryRef | undefined, UseBackgroundQueryResult, ] { return wrapHook( @@ -200,7 +197,7 @@ function _useBackgroundQuery< Partial>) | BackgroundQueryHookOptionsNoInfer ): [ - QueryReference | undefined, + QueryRef | undefined, UseBackgroundQueryResult, ] { const client = useApolloClient(options.client); diff --git a/src/react/hooks/useLoadableQuery.ts b/src/react/hooks/useLoadableQuery.ts index 7c0c0cca4e6..00249b08e76 100644 --- a/src/react/hooks/useLoadableQuery.ts +++ b/src/react/hooks/useLoadableQuery.ts @@ -8,12 +8,13 @@ import type { } from "../../core/index.js"; import { useApolloClient } from "./useApolloClient.js"; import { + assertWrappedQueryRef, getSuspenseCache, unwrapQueryRef, updateWrappedQueryRef, wrapQueryRef, } from "../internal/index.js"; -import type { CacheKey, QueryReference } from "../internal/index.js"; +import type { CacheKey, QueryRef } from "../internal/index.js"; import type { LoadableQueryHookOptions } from "../types/types.js"; import { __use, useRenderGuard } from "./internal/index.js"; import { useWatchQueryOptions } from "./useSuspenseQuery.js"; @@ -42,7 +43,7 @@ export type UseLoadableQueryResult< TVariables extends OperationVariables = OperationVariables, > = [ loadQuery: LoadQueryFunction, - queryRef: QueryReference | null, + queryRef: QueryRef | null, { /** {@inheritDoc @apollo/client!QueryResultDocumentation#fetchMore:member} */ fetchMore: FetchMoreFunction; @@ -168,11 +169,13 @@ export function useLoadableQuery< const watchQueryOptions = useWatchQueryOptions({ client, query, options }); const { queryKey = [] } = options; - const [queryRef, setQueryRef] = React.useState | null>(null); + assertWrappedQueryRef(queryRef); + const internalQueryRef = queryRef && unwrapQueryRef(queryRef); if (queryRef && internalQueryRef?.didChangeOptions(watchQueryOptions)) { diff --git a/src/react/hooks/useQueryRefHandlers.ts b/src/react/hooks/useQueryRefHandlers.ts index 0d6809e6ca6..a62149360aa 100644 --- a/src/react/hooks/useQueryRefHandlers.ts +++ b/src/react/hooks/useQueryRefHandlers.ts @@ -1,14 +1,12 @@ import * as React from "rehackt"; import { + assertWrappedQueryRef, getWrappedPromise, unwrapQueryRef, updateWrappedQueryRef, wrapQueryRef, } from "../internal/index.js"; -import type { - InternalQueryReference, - QueryReference, -} from "../internal/index.js"; +import type { QueryRef } from "../internal/index.js"; import type { OperationVariables } from "../../core/types.js"; import type { RefetchFunction, FetchMoreFunction } from "./useSuspenseQuery.js"; import type { FetchMoreQueryOptions } from "../../core/watchQueryOptions.js"; @@ -42,22 +40,15 @@ export interface UseQueryRefHandlersResult< * } * ``` * @since 3.9.0 - * @param queryRef - A `QueryReference` returned from `useBackgroundQuery`, `useLoadableQuery`, or `createQueryPreloader`. + * @param queryRef - A `QueryRef` returned from `useBackgroundQuery`, `useLoadableQuery`, or `createQueryPreloader`. */ export function useQueryRefHandlers< TData = unknown, TVariables extends OperationVariables = OperationVariables, >( - queryRef: QueryReference + queryRef: QueryRef ): UseQueryRefHandlersResult { - const unwrapped = unwrapQueryRef( - queryRef - ) satisfies InternalQueryReference as /* - by all rules of this codebase, this should never be undefined - but if `queryRef` is a transported object, it cannot have a - `QUERY_REFERENCE_SYMBOL` symbol property, so the call above - will return `undefined` and we want that represented in the type - */ InternalQueryReference | undefined; + const unwrapped = unwrapQueryRef(queryRef); return wrapHook( "useQueryRefHandlers", @@ -76,8 +67,9 @@ function _useQueryRefHandlers< TData = unknown, TVariables extends OperationVariables = OperationVariables, >( - queryRef: QueryReference + queryRef: QueryRef ): UseQueryRefHandlersResult { + assertWrappedQueryRef(queryRef); const [previousQueryRef, setPreviousQueryRef] = React.useState(queryRef); const [wrappedQueryRef, setWrappedQueryRef] = React.useState(queryRef); const internalQueryRef = unwrapQueryRef(queryRef); diff --git a/src/react/hooks/useReadQuery.ts b/src/react/hooks/useReadQuery.ts index 0b600c59f34..e3a9836b0b5 100644 --- a/src/react/hooks/useReadQuery.ts +++ b/src/react/hooks/useReadQuery.ts @@ -1,13 +1,11 @@ import * as React from "rehackt"; import { + assertWrappedQueryRef, getWrappedPromise, unwrapQueryRef, updateWrappedQueryRef, } from "../internal/index.js"; -import type { - InternalQueryReference, - QueryReference, -} from "../internal/index.js"; +import type { QueryRef } from "../internal/index.js"; import { __use, wrapHook } from "./internal/index.js"; import { toApolloError } from "./useSuspenseQuery.js"; import { useSyncExternalStore } from "./useSyncExternalStore.js"; @@ -41,16 +39,9 @@ export interface UseReadQueryResult { } export function useReadQuery( - queryRef: QueryReference + queryRef: QueryRef ): UseReadQueryResult { - const unwrapped = unwrapQueryRef( - queryRef - ) satisfies InternalQueryReference as /* - by all rules of this codebase, this should never be undefined - but if `queryRef` is a transported object, it cannot have a - `QUERY_REFERENCE_SYMBOL` symbol property, so the call above - will return `undefined` and we want that represented in the type - */ InternalQueryReference | undefined; + const unwrapped = unwrapQueryRef(queryRef); return wrapHook( "useReadQuery", @@ -66,8 +57,9 @@ export function useReadQuery( } function _useReadQuery( - queryRef: QueryReference + queryRef: QueryRef ): UseReadQueryResult { + assertWrappedQueryRef(queryRef); const internalQueryRef = React.useMemo( () => unwrapQueryRef(queryRef), [queryRef] diff --git a/src/react/internal/cache/QueryReference.ts b/src/react/internal/cache/QueryReference.ts index 16a014d0d89..b6279efd24c 100644 --- a/src/react/internal/cache/QueryReference.ts +++ b/src/react/internal/cache/QueryReference.ts @@ -16,6 +16,7 @@ import { } from "../../../utilities/index.js"; import type { QueryKey } from "./types.js"; import { wrapPromiseWithState } from "../../../utilities/index.js"; +import { invariant } from "../../../utilities/globals/invariantWrappers.js"; type QueryRefPromise = PromiseWithState>; @@ -27,17 +28,51 @@ type FetchMoreOptions = Parameters< const QUERY_REFERENCE_SYMBOL: unique symbol = Symbol(); const PROMISE_SYMBOL: unique symbol = Symbol(); - +declare const QUERY_REF_BRAND: unique symbol; /** * A `QueryReference` is an opaque object returned by `useBackgroundQuery`. * A child component reading the `QueryReference` via `useReadQuery` will * suspend until the promise resolves. */ -export interface QueryReference { +export interface QueryRef { + /** @internal */ + [QUERY_REF_BRAND]?(variables: TVariables): TData; +} + +/** + * @internal + * For usage in internal helpers only. + */ +interface WrappedQueryRef + extends QueryRef { /** @internal */ readonly [QUERY_REFERENCE_SYMBOL]: InternalQueryReference; /** @internal */ [PROMISE_SYMBOL]: QueryRefPromise; + /** @internal */ + toPromise?(): Promise; +} + +/** + * @deprecated Please use the `QueryRef` interface instead of `QueryReference`. + * + * {@inheritDoc @apollo/client!QueryRef:interface} + */ +export interface QueryReference + extends QueryRef { + /** + * @deprecated Please use the `QueryRef` interface instead of `QueryReference`. + * + * {@inheritDoc @apollo/client!PreloadedQueryRef#toPromise:member(1)} + */ + toPromise?: unknown; +} + +/** + * {@inheritDoc @apollo/client!QueryRef:interface} + */ +export interface PreloadedQueryRef + extends QueryRef { /** * A function that returns a promise that resolves when the query has finished * loading. The promise resolves with the `QueryReference` itself. @@ -75,7 +110,7 @@ export interface QueryReference { * * @since 3.9.0 */ - toPromise(): Promise>; + toPromise(): Promise>; } interface InternalQueryReferenceOptions { @@ -86,7 +121,7 @@ interface InternalQueryReferenceOptions { export function wrapQueryRef( internalQueryRef: InternalQueryReference ) { - const ref: QueryReference = { + const ref: WrappedQueryRef = { toPromise() { // We avoid resolving this promise with the query data because we want to // discourage using the server data directly from the queryRef. Instead, @@ -108,7 +143,24 @@ export function wrapQueryRef( return ref; } -export function getWrappedPromise(queryRef: QueryReference) { +export function assertWrappedQueryRef( + queryRef: QueryRef +): asserts queryRef is WrappedQueryRef; +export function assertWrappedQueryRef( + queryRef: QueryRef | undefined | null +): asserts queryRef is WrappedQueryRef | undefined | null; +export function assertWrappedQueryRef( + queryRef: QueryRef | undefined | null +) { + invariant( + !queryRef || QUERY_REFERENCE_SYMBOL in queryRef, + "Expected a QueryRef object, but got something else instead." + ); +} + +export function getWrappedPromise( + queryRef: WrappedQueryRef +) { const internalQueryRef = unwrapQueryRef(queryRef); return internalQueryRef.promise.status === "fulfilled" ? @@ -117,13 +169,19 @@ export function getWrappedPromise(queryRef: QueryReference) { } export function unwrapQueryRef( - queryRef: QueryReference -): InternalQueryReference { + queryRef: WrappedQueryRef +): InternalQueryReference; +export function unwrapQueryRef( + queryRef: Partial> +): undefined | InternalQueryReference; +export function unwrapQueryRef( + queryRef: Partial> +) { return queryRef[QUERY_REFERENCE_SYMBOL]; } export function updateWrappedQueryRef( - queryRef: QueryReference, + queryRef: WrappedQueryRef, promise: QueryRefPromise ) { queryRef[PROMISE_SYMBOL] = promise; diff --git a/src/react/internal/cache/__tests__/QueryReference.test.ts b/src/react/internal/cache/__tests__/QueryReference.test.ts deleted file mode 100644 index 7e015109333..00000000000 --- a/src/react/internal/cache/__tests__/QueryReference.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - ApolloClient, - ApolloLink, - InMemoryCache, - Observable, -} from "../../../../core"; -import { setupSimpleCase } from "../../../../testing/internal"; -import { InternalQueryReference } from "../QueryReference"; - -test("kicks off request immediately when created", async () => { - const { query } = setupSimpleCase(); - let fetchCount = 0; - - const client = new ApolloClient({ - cache: new InMemoryCache(), - link: new ApolloLink((operation) => { - fetchCount++; - return Observable.of({ data: { greeting: "Hello" } }); - }), - }); - - const observable = client.watchQuery({ query }); - - expect(fetchCount).toBe(0); - new InternalQueryReference(observable, {}); - expect(fetchCount).toBe(1); -}); diff --git a/src/react/internal/cache/__tests__/QueryReference.test.tsx b/src/react/internal/cache/__tests__/QueryReference.test.tsx new file mode 100644 index 00000000000..13cf85b3586 --- /dev/null +++ b/src/react/internal/cache/__tests__/QueryReference.test.tsx @@ -0,0 +1,281 @@ +import { + ApolloClient, + ApolloLink, + InMemoryCache, + Observable, +} from "../../../../core"; +import { setupSimpleCase } from "../../../../testing/internal"; +import { + InternalQueryReference, + PreloadedQueryRef, + QueryRef, + QueryReference, +} from "../QueryReference"; +import React from "react"; + +test("kicks off request immediately when created", async () => { + const { query } = setupSimpleCase(); + let fetchCount = 0; + + const client = new ApolloClient({ + cache: new InMemoryCache(), + link: new ApolloLink((operation) => { + fetchCount++; + return Observable.of({ data: { greeting: "Hello" } }); + }), + }); + + const observable = client.watchQuery({ query }); + + expect(fetchCount).toBe(0); + new InternalQueryReference(observable, {}); + expect(fetchCount).toBe(1); +}); + +test.skip("type tests", () => { + test("passing as prop", () => { + const ANY: any = {}; + + interface Data { + foo: string; + } + interface Vars { + bar: string; + } + function ComponentWithQueryRefProp< + TData = unknown, + TVariables = unknown, + >({}: { queryRef: QueryRef }) { + return null; + } + function ComponentWithQueryReferenceProp< + TData = unknown, + TVariables = unknown, + >({}: { queryRef: QueryReference }) { + return null; + } + function ComponentWithPreloadedQueryRefProp< + TData = unknown, + TVariables = unknown, + >({}: { queryRef: PreloadedQueryRef }) { + return null; + } + + { + const withoutTypes: QueryRef = ANY; + const withData: QueryRef = ANY; + const withDataAndVariables: QueryRef = ANY; + + <> + {/* passing queryRef into components that expect queryRef */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + queryRef={withDataAndVariables} /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + {/* passing queryRef into components that expect queryReference */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + {/* passing queryRef into components that expect preloadedQueryRef */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + /* @ts-expect-error */ + queryRef={withData} + /> + /* @ts-expect-error */ + queryRef={withDataAndVariables} + /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + /* @ts-expect-error */ + queryRef={withData} + /> + /* @ts-expect-error */ + queryRef={withDataAndVariables} + /> + + ; + } + { + const withoutTypes: QueryReference = ANY; + const withData: QueryReference = ANY; + const withDataAndVariables: QueryReference = ANY; + <> + {/* passing queryReference into components that expect queryRef */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + queryRef={withDataAndVariables} /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + {/* passing queryReference into components that expect queryReference */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + {/* passing queryReference into components that expect preloadedQueryRef */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + /* @ts-expect-error */ + queryRef={withData} + /> + /* @ts-expect-error */ + queryRef={withDataAndVariables} + /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + /* @ts-expect-error */ + queryRef={withData} + /> + /* @ts-expect-error */ + queryRef={withDataAndVariables} + /> + + ; + } + { + const withoutTypes: PreloadedQueryRef = ANY; + const withData: PreloadedQueryRef = ANY; + const withDataAndVariables: PreloadedQueryRef = ANY; + <> + {/* passing preloadedQueryRef into components that expect queryRef */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + queryRef={withDataAndVariables} /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + {/* passing preloadedQueryRef into components that expect queryReference */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + {/* passing preloadedQueryRef into components that expect preloadedQueryRef */} + <> + + + + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + /* @ts-expect-error */ + queryRef={withoutTypes} + /> + queryRef={withData} /> + + queryRef={withDataAndVariables} + /> + + ; + } + }); +}); diff --git a/src/react/internal/index.ts b/src/react/internal/index.ts index a453c6f802c..7768265bf9c 100644 --- a/src/react/internal/index.ts +++ b/src/react/internal/index.ts @@ -1,12 +1,17 @@ export { getSuspenseCache } from "./cache/getSuspenseCache.js"; export type { CacheKey, QueryKey } from "./cache/types.js"; -export type { QueryReference } from "./cache/QueryReference.js"; +export type { + QueryReference, + QueryRef, + PreloadedQueryRef, +} from "./cache/QueryReference.js"; export { InternalQueryReference, getWrappedPromise, unwrapQueryRef, updateWrappedQueryRef, wrapQueryRef, + assertWrappedQueryRef, } from "./cache/QueryReference.js"; export type { SuspenseCacheOptions } from "./cache/SuspenseCache.js"; export type { HookWrappers } from "../hooks/internal/wrapHook.js"; diff --git a/src/react/query-preloader/__tests__/createQueryPreloader.test.tsx b/src/react/query-preloader/__tests__/createQueryPreloader.test.tsx index 9b88fd385c9..8ab59054dd6 100644 --- a/src/react/query-preloader/__tests__/createQueryPreloader.test.tsx +++ b/src/react/query-preloader/__tests__/createQueryPreloader.test.tsx @@ -17,7 +17,7 @@ import { wait, } from "../../../testing"; import { expectTypeOf } from "expect-type"; -import { QueryReference, unwrapQueryRef } from "../../internal"; +import { PreloadedQueryRef, QueryRef, unwrapQueryRef } from "../../internal"; import { DeepPartial, Observable } from "../../../utilities"; import { SimpleCaseData, @@ -48,7 +48,7 @@ function renderDefaultTestApp({ queryRef, }: { client: ApolloClient; - queryRef: QueryReference; + queryRef: QueryRef; }) { const Profiler = createProfiler({ initialSnapshot: { @@ -2271,7 +2271,9 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query); - expectTypeOf(queryRef).toEqualTypeOf>(); + expectTypeOf(queryRef).toEqualTypeOf< + PreloadedQueryRef + >(); }); test("returns QueryReference in default case", () => { @@ -2280,7 +2282,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } @@ -2289,7 +2291,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } }); @@ -2300,7 +2302,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query, { errorPolicy: "ignore" }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } @@ -2311,7 +2313,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } }); @@ -2322,7 +2324,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query, { errorPolicy: "all" }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } @@ -2333,7 +2335,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } }); @@ -2344,7 +2346,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query, { errorPolicy: "none" }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } @@ -2355,7 +2357,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } }); @@ -2366,7 +2368,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query, { returnPartialData: true }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference, { [key: string]: any }> + PreloadedQueryRef, { [key: string]: any }> >(); } @@ -2377,7 +2379,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference, OperationVariables> + PreloadedQueryRef, OperationVariables> >(); } }); @@ -2387,7 +2389,9 @@ describe.skip("type tests", () => { const query: TypedDocumentNode = gql``; const queryRef = preloadQuery(query, { returnPartialData: false }); - expectTypeOf(queryRef).toEqualTypeOf>(); + expectTypeOf(queryRef).toEqualTypeOf< + PreloadedQueryRef + >(); } { @@ -2396,7 +2400,9 @@ describe.skip("type tests", () => { returnPartialData: false, }); - expectTypeOf(queryRef).toEqualTypeOf>(); + expectTypeOf(queryRef).toEqualTypeOf< + PreloadedQueryRef + >(); } }); @@ -2406,7 +2412,7 @@ describe.skip("type tests", () => { const queryRef = preloadQuery(query, { canonizeResults: true }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } @@ -2417,7 +2423,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference + PreloadedQueryRef >(); } }); @@ -2431,7 +2437,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference< + PreloadedQueryRef< DeepPartial | undefined, { [key: string]: any } > @@ -2446,7 +2452,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference< + PreloadedQueryRef< DeepPartial | undefined, OperationVariables > @@ -2461,7 +2467,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference, { [key: string]: any }> + PreloadedQueryRef, { [key: string]: any }> >(); } @@ -2473,7 +2479,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference, OperationVariables> + PreloadedQueryRef, OperationVariables> >(); } }); @@ -2488,7 +2494,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference, { [key: string]: any }> + PreloadedQueryRef, { [key: string]: any }> >(); } @@ -2501,7 +2507,7 @@ describe.skip("type tests", () => { }); expectTypeOf(queryRef).toEqualTypeOf< - QueryReference, OperationVariables> + PreloadedQueryRef, OperationVariables> >(); } }); diff --git a/src/react/query-preloader/createQueryPreloader.ts b/src/react/query-preloader/createQueryPreloader.ts index 606ca5e2101..226723dab9a 100644 --- a/src/react/query-preloader/createQueryPreloader.ts +++ b/src/react/query-preloader/createQueryPreloader.ts @@ -14,7 +14,7 @@ import type { OnlyRequiredProperties, } from "../../utilities/index.js"; import { InternalQueryReference, wrapQueryRef } from "../internal/index.js"; -import type { QueryReference } from "../internal/index.js"; +import type { PreloadedQueryRef } from "../internal/index.js"; import type { NoInfer } from "../index.js"; type VariablesOption = @@ -105,7 +105,7 @@ export interface PreloadQueryFunction { >( query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg, TOptions> - ): QueryReference< + ): PreloadedQueryRef< TOptions["errorPolicy"] extends "ignore" | "all" ? TOptions["returnPartialData"] extends true ? DeepPartial | undefined @@ -122,7 +122,7 @@ export interface PreloadQueryFunction { returnPartialData: true; errorPolicy: "ignore" | "all"; } - ): QueryReference | undefined, TVariables>; + ): PreloadedQueryRef | undefined, TVariables>; /** {@inheritDoc @apollo/client!PreloadQueryFunction:interface} */ ( @@ -130,7 +130,7 @@ export interface PreloadQueryFunction { options: PreloadQueryOptions> & { errorPolicy: "ignore" | "all"; } - ): QueryReference; + ): PreloadedQueryRef; /** {@inheritDoc @apollo/client!PreloadQueryFunction:interface} */ ( @@ -138,13 +138,13 @@ export interface PreloadQueryFunction { options: PreloadQueryOptions> & { returnPartialData: true; } - ): QueryReference, TVariables>; + ): PreloadedQueryRef, TVariables>; /** {@inheritDoc @apollo/client!PreloadQueryFunction:interface} */ ( query: DocumentNode | TypedDocumentNode, ...[options]: PreloadQueryOptionsArg> - ): QueryReference; + ): PreloadedQueryRef; } /** @@ -175,7 +175,7 @@ export function createQueryPreloader( query: DocumentNode | TypedDocumentNode, options: PreloadQueryOptions> & VariablesOption = Object.create(null) - ): QueryReference { + ): PreloadedQueryRef { const queryRef = new InternalQueryReference( client.watchQuery({ ...options, @@ -187,6 +187,6 @@ export function createQueryPreloader( } ); - return wrapQueryRef(queryRef); + return wrapQueryRef(queryRef) as PreloadedQueryRef; }; } diff --git a/src/react/types/types.ts b/src/react/types/types.ts index ea0c98a26b8..41cff9e8835 100644 --- a/src/react/types/types.ts +++ b/src/react/types/types.ts @@ -32,7 +32,11 @@ import type { /* QueryReference type */ -export type { QueryReference } from "../internal/index.js"; +export type { + QueryReference, + QueryRef, + PreloadedQueryRef, +} from "../internal/index.js"; /* Common types */ diff --git a/src/testing/matchers/index.d.ts b/src/testing/matchers/index.d.ts index b73b33cfd08..65fbcc37ba9 100644 --- a/src/testing/matchers/index.d.ts +++ b/src/testing/matchers/index.d.ts @@ -3,7 +3,7 @@ import type { DocumentNode, OperationVariables, } from "../../core/index.js"; -import type { QueryReference } from "../../react/index.js"; +import type { QueryRef } from "../../react/index.js"; import { NextRenderOptions, Profiler, @@ -15,8 +15,8 @@ interface ApolloCustomMatchers { /** * Used to determine if a queryRef has been disposed. */ - toBeDisposed: T extends QueryReference ? () => R - : { error: "matcher needs to be called on a QueryReference" }; + toBeDisposed: T extends QueryRef ? () => R + : { error: "matcher needs to be called on a QueryRef" }; /** * Used to determine if two GraphQL query documents are equal to each other by * comparing their printed values. The document must be parsed by `gql`. diff --git a/src/testing/matchers/toBeDisposed.ts b/src/testing/matchers/toBeDisposed.ts index b9ca3c6199c..7b8d9461a8b 100644 --- a/src/testing/matchers/toBeDisposed.ts +++ b/src/testing/matchers/toBeDisposed.ts @@ -1,26 +1,17 @@ import type { MatcherFunction } from "expect"; -import type { QueryReference } from "../../react/internal/index.js"; +import type { QueryRef } from "../../react/internal/index.js"; import { - InternalQueryReference, + assertWrappedQueryRef, unwrapQueryRef, } from "../../react/internal/index.js"; -function isQueryRef(queryRef: unknown): queryRef is QueryReference { - try { - return unwrapQueryRef(queryRef as any) instanceof InternalQueryReference; - } catch (e) { - return false; - } -} - -export const toBeDisposed: MatcherFunction<[]> = function (queryRef) { +export const toBeDisposed: MatcherFunction<[]> = function (_queryRef) { const hint = this.utils.matcherHint("toBeDisposed", "queryRef", "", { isNot: this.isNot, }); - if (!isQueryRef(queryRef)) { - throw new Error(`\n${hint}\n\nmust be called with a valid QueryReference`); - } + const queryRef = _queryRef as QueryRef; + assertWrappedQueryRef(queryRef); const pass = unwrapQueryRef(queryRef).disposed;