diff --git a/.api-reports/api-report-cache.api.md b/.api-reports/api-report-cache.api.md index 44469bb84a8..ca4bd747f58 100644 --- a/.api-reports/api-report-cache.api.md +++ b/.api-reports/api-report-cache.api.md @@ -34,6 +34,7 @@ import type { StoreObject } from '@apollo/client/utilities'; import type { StoreValue } from '@apollo/client/utilities'; import { Trie } from '@wry/trie'; import type { TypedDocumentNode } from '@apollo/client'; +import type { TypeOverrides } from '@apollo/client'; import type { Unmasked } from '@apollo/client/masking'; // Warning: (ae-forgotten-export) The symbol "StoreObjectValueMaybeReference" needs to be exported by the entry point index.d.ts @@ -165,7 +166,7 @@ type BroadcastOptions = Pick, "optimistic" | // @public (undocumented) namespace Cache_2 { // (undocumented) - interface BatchOptions { + interface BatchOptions { onWatchUpdated?: (this: TCache, watch: Cache_2.WatchOptions, diff: Cache_2.DiffResult, lastDiff?: Cache_2.DiffResult | undefined) => any; optimistic?: string | boolean; removeOptimistic?: string; @@ -206,6 +207,10 @@ namespace Cache_2 { id?: string; } // (undocumented) + type Implementation = TypeOverrides extends { + cache: infer TCache; + } ? TCache extends ApolloCache ? TCache : "The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type." : ApolloCache; + // (undocumented) interface ModifyOptions = Record> { // (undocumented) broadcast?: boolean; diff --git a/.api-reports/api-report-core.api.md b/.api-reports/api-report-core.api.md index ff04f3d158e..e80fcd5f985 100644 --- a/.api-reports/api-report-core.api.md +++ b/.api-reports/api-report-core.api.md @@ -216,7 +216,7 @@ export namespace ApolloClient { } // (undocumented) export namespace DocumentationTypes { - export function mutate(options: ApolloClient.MutateOptions): Promise>>; + export function mutate(options: ApolloClient.MutateOptions): Promise>>; export function query(options: ApolloClient.QueryOptions): Promise>>; } // (undocumented) @@ -232,18 +232,18 @@ export namespace ApolloClient { export interface DefaultOptions extends ApolloClient.DefaultOptions.Mutate.Calculated { } // (undocumented) - export type ResultForOptions | MutateOptions> = LazyType, OptionWithFallback & ErrorPolicy>>; + export type ResultForOptions | MutateOptions> = LazyType, OptionWithFallback & ErrorPolicy>>; export interface Signature extends Signatures.Evaluated { } // (undocumented) export namespace Signatures { // (undocumented) export interface Classic { - (options: ApolloClient.MutateOptions & { + (options: ApolloClient.MutateOptions & { errorPolicy?: TErrorPolicy; }): Promise, TErrorPolicy>>; // @deprecated (undocumented) - (options: ApolloClient.MutateOptions & (TErrorPolicy extends undefined ? {} : { + (options: ApolloClient.MutateOptions & (TErrorPolicy extends undefined ? {} : { errorPolicy: TErrorPolicy; })): Promise, TErrorPolicy>>; } @@ -251,16 +251,16 @@ export namespace ApolloClient { export type Evaluated = SignatureStyle extends "classic" ? Classic : Modern; // (undocumented) export interface Modern { - , NoInfer, TCache> & VariablesOption, NoInfer, Cache_2.Implementation> & VariablesOption]?: never; }>>(options: TOptions & { mutation: TypedDocumentNode; - }): Promise>; + }): Promise>; } } } // (undocumented) - export type MutateOptions = { + export type MutateOptions = { optimisticResponse?: Unmasked> | ((vars: TVariables, { IGNORE }: { IGNORE: IgnoreModifier; }) => Unmasked> | IgnoreModifier); @@ -305,7 +305,7 @@ export namespace ApolloClient { // (undocumented) export interface Options extends InternalTypes_2.DefaultOptionsParentObject { assumeImmutableResults?: boolean; - cache: ApolloCache; + cache: Cache_2.Implementation; // (undocumented) clientAwareness?: ClientAwarenessLink.ClientAwarenessOptions; dataMasking?: boolean; @@ -390,7 +390,7 @@ export namespace ApolloClient { export type ReadFragmentOptions = Base.ReadFragmentOptions & VariablesOption & Cache_2.CacheIdentifierOption; // (undocumented) export type ReadQueryOptions = Base.ReadQueryOptions & VariablesOption; - export interface RefetchQueriesOptions { + export interface RefetchQueriesOptions { include?: RefetchQueriesInclude; onQueryUpdated?: OnQueryUpdated | null; optimistic?: boolean; @@ -453,7 +453,7 @@ export class ApolloClient { // (undocumented) __requestRaw(request: ApolloLink.Request): Observable_2>; // (undocumented) - cache: ApolloCache; + cache: Cache_2.Implementation; clearStore(): Promise; // (undocumented) get defaultContext(): Partial; @@ -491,7 +491,7 @@ export class ApolloClient { // @deprecated reFetchObservableQueries: (includeStandby?: boolean) => Promise[]>; refetchObservableQueries(includeStandby?: boolean): Promise[]>; - refetchQueries>>(options: ApolloClient.RefetchQueriesOptions): ApolloClient.RefetchQueriesResult; + refetchQueries>>(options: ApolloClient.RefetchQueriesOptions): ApolloClient.RefetchQueriesResult; resetStore(): Promise[] | null>; restore(serializedState: unknown): ApolloCache; setLink(newLink: ApolloLink): void; @@ -732,7 +732,7 @@ export type MutateResult = ApolloClient.MutateResult; export type MutationFetchPolicy = Extract; // @public @deprecated (undocumented) -export type MutationOptions = ApolloClient.MutateOptions; +export type MutationOptions = ApolloClient.MutateOptions; // @public (undocumented) export type MutationQueryReducer = (previousResult: Record, options: { @@ -761,7 +761,7 @@ interface MutationStoreValue { } // @public (undocumented) -export type MutationUpdaterFunction = (cache: TCache, result: FormattedExecutionResult>, options: { +export type MutationUpdaterFunction = (cache: TCache, result: FormattedExecutionResult>, options: { context?: DefaultContext; variables?: TVariables; }) => void; @@ -1059,7 +1059,7 @@ class QueryManager { // (undocumented) maskOperation(options: MaskOperationOptions): MaybeMasked; // (undocumented) - mutate({ mutation, variables, optimisticResponse, updateQueries, refetchQueries, awaitRefetchQueries, update: updateWithProxyFn, onQueryUpdated, fetchPolicy, errorPolicy, keepRootFields, context, }: ApolloClient.MutateOptions & { + mutate({ mutation, variables, optimisticResponse, updateQueries, refetchQueries, awaitRefetchQueries, update: updateWithProxyFn, onQueryUpdated, fetchPolicy, errorPolicy, keepRootFields, context, }: ApolloClient.MutateOptions & { errorPolicy: ErrorPolicy; fetchPolicy: MutationFetchPolicy; }): Promise>>; @@ -1074,7 +1074,7 @@ class QueryManager { // (undocumented) refetchObservableQueries(includeStandby?: boolean): Promise[]>; // (undocumented) - refetchQueries({ updateCache, include, optimistic, removeOptimistic, onQueryUpdated, }: InternalRefetchQueriesOptions): InternalRefetchQueriesMap; + refetchQueries({ updateCache, include, optimistic, removeOptimistic, onQueryUpdated, }: InternalRefetchQueriesOptions): InternalRefetchQueriesMap; // (undocumented) readonly ssrMode: boolean; // (undocumented) @@ -1224,7 +1224,7 @@ export type RefetchQueriesInclude = RefetchQueryDescriptor[] | RefetchQueriesInc type RefetchQueriesIncludeShorthand = "all" | "active"; // @public @deprecated (undocumented) -export type RefetchQueriesOptions = ApolloClient.RefetchQueriesOptions; +export type RefetchQueriesOptions = ApolloClient.RefetchQueriesOptions; // @public (undocumented) export type RefetchQueriesPromiseResults = IsAny extends true ? any[] : TResult extends boolean ? ApolloClient.QueryResult[] : TResult extends PromiseLike ? U[] : TResult[]; @@ -1367,7 +1367,7 @@ export const windowFocusSource: RefetchEventManager.EventSource; // Warnings were encountered during analysis: // -// src/core/ApolloClient.ts:633:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts +// src/core/ApolloClient.ts:635:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts // src/core/ObservableQuery.ts:375:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts // src/core/QueryManager.ts:195:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts diff --git a/.api-reports/api-report-react.api.md b/.api-reports/api-report-react.api.md index a420323c002..cdb61e31f43 100644 --- a/.api-reports/api-report-react.api.md +++ b/.api-reports/api-report-react.api.md @@ -4,9 +4,10 @@ ```ts -import type { ApolloCache } from '@apollo/client'; -import type { ApolloCache as ApolloCache_2 } from '@apollo/client/cache'; +import type { ApolloCache } from '@apollo/client/cache'; +import type { ApolloCache as ApolloCache_2 } from '@apollo/client'; import type { ApolloClient } from '@apollo/client'; +import type { Cache as Cache_2 } from '@apollo/client/cache'; import type { DataState } from '@apollo/client'; import type { DataValue } from '@apollo/client'; import type { DefaultContext } from '@apollo/client'; @@ -130,16 +131,16 @@ type MakeRequiredVariablesOptional>; // @public @deprecated (undocumented) -export type MutationFunctionOptions = useMutation.MutationFunctionOptions; +export type MutationFunctionOptions = useMutation.MutationFunctionOptions; // @public @deprecated (undocumented) -export type MutationHookOptions = useMutation.Options; +export type MutationHookOptions = useMutation.Options; // @public @deprecated (undocumented) export type MutationResult = useMutation.Result; // @public @deprecated (undocumented) -export type MutationTuple = useMutation.ResultTuple; +export type MutationTuple = useMutation.ResultTuple; // @public @deprecated (undocumented) export type OnDataOptions = useSubscription.OnDataOptions; @@ -607,7 +608,7 @@ export namespace useFragment { export namespace DocumentationTypes { export function useFragment({ fragment, from, fragmentName, variables, optimistic, client, }: useFragment.Options): useFragment.Result; } - export type FromOptionValue = ApolloCache_2.FromOptionValue; + export type FromOptionValue = ApolloCache.FromOptionValue; // (undocumented) export interface Options { client?: ApolloClient; @@ -913,7 +914,7 @@ export namespace useMutation { } } // (undocumented) - export type MutationFunction = (...[options]: {} extends TVariables ? [ + export type MutationFunction = (...[options]: {} extends TVariables ? [ options?: MutationFunctionOptions & { variables?: TVariables; } @@ -923,11 +924,11 @@ export namespace useMutation { } ]) => Promise, TErrorPolicy>>; // (undocumented) - export type MutationFunctionOptions = Options & { + export type MutationFunctionOptions = Options & { context?: DefaultContext | ((hookContext: DefaultContext | undefined) => DefaultContext); }; // (undocumented) - export interface Options = Partial> { + export interface Options = Partial> { awaitRefetchQueries?: boolean; client?: ApolloClient; context?: DefaultContext; @@ -952,7 +953,7 @@ export namespace useMutation { // Warning: (ae-forgotten-export) The symbol "ExtractConfiguredVariables" needs to be exported by the entry point index.d.ts // // (undocumented) - export type ResultForOptions | Options, TErrorPolicy extends ErrorPolicy | undefined = undefined> = LazyType>, TCache, [ + export type ResultForOptions | Options, TErrorPolicy extends ErrorPolicy | undefined = undefined> = LazyType>, TCache, [ TErrorPolicy ] extends [undefined] ? DefaultOptions extends { errorPolicy: infer D; @@ -976,7 +977,7 @@ export namespace useMutation { }; }; // (undocumented) - export type ResultTuple = [ + export type ResultTuple = [ mutate: MutationFunction, result: Result ]; @@ -988,13 +989,13 @@ export namespace useMutation { // (undocumented) export interface Classic { // (undocumented) - = {}, TErrorPolicy extends ErrorPolicy | undefined = undefined>(mutation: DocumentNode_2 | TypedDocumentNode, options?: useMutation.Options, NoInfer_2, ApolloCache, { + = {}, TErrorPolicy extends ErrorPolicy | undefined = undefined>(mutation: DocumentNode_2 | TypedDocumentNode, options?: useMutation.Options, NoInfer_2, Cache_2.Implementation, { [K in keyof TConfiguredVariables]: K extends keyof TVariables ? TConfiguredVariables[K] : never; }> & { errorPolicy?: TErrorPolicy; - }): useMutation.ResultTuple, ApolloCache, TErrorPolicy>; + }): useMutation.ResultTuple, Cache_2.Implementation, TErrorPolicy>; // @deprecated (undocumented) - = {}, TErrorPolicy extends ErrorPolicy | undefined = undefined>(mutation: DocumentNode_2 | TypedDocumentNode, options?: useMutation.Options, NoInfer_2, TCache, { + = {}, TErrorPolicy extends ErrorPolicy | undefined = undefined>(mutation: DocumentNode_2 | TypedDocumentNode, options?: useMutation.Options, NoInfer_2, TCache, { [K in keyof TConfiguredVariables]: K extends keyof TVariables ? TConfiguredVariables[K] : never; }> & (TErrorPolicy extends undefined ? {} : { errorPolicy: TErrorPolicy; @@ -1005,15 +1006,15 @@ export namespace useMutation { // (undocumented) export interface Modern { // (undocumented) - (mutation: DocumentNode_2 | TypedDocumentNode): useMutation.ResultForOptions>; + (mutation: DocumentNode_2 | TypedDocumentNode): useMutation.ResultForOptions>; // (undocumented) - , NoInfer_2, TCache> & { + , NoInfer_2, Cache_2.Implementation> & { variables?: { [K in Exclude]?: never; }; }, TErrorPolicy extends ErrorPolicy | undefined = undefined>(mutation: DocumentNode_2 | TypedDocumentNode, options?: TOptions & { errorPolicy?: TErrorPolicy; - }): useMutation.ResultForOptions; + }): useMutation.ResultForOptions; } } } @@ -1384,7 +1385,7 @@ export namespace useSuspenseFragment { export namespace DocumentationTypes { export function useSuspenseFragment(options: useSuspenseFragment.Options): useSuspenseFragment.Result; } - export type FromOptionValue = ApolloCache_2.FromOptionValue; + export type FromOptionValue = ApolloCache.FromOptionValue; // (undocumented) export type Options = Base.Options & VariablesOption>; // (undocumented) diff --git a/.api-reports/api-report.api.md b/.api-reports/api-report.api.md index 30fe49a5ef4..4e07b5ba563 100644 --- a/.api-reports/api-report.api.md +++ b/.api-reports/api-report.api.md @@ -257,7 +257,7 @@ export namespace ApolloClient { } // (undocumented) export namespace DocumentationTypes { - export function mutate(options: ApolloClient.MutateOptions): Promise>>; + export function mutate(options: ApolloClient.MutateOptions): Promise>>; export function query(options: ApolloClient.QueryOptions): Promise>>; } // (undocumented) @@ -276,18 +276,18 @@ export namespace ApolloClient { // Warning: (ae-forgotten-export) The symbol "OptionWithFallback" needs to be exported by the entry point index.d.ts // // (undocumented) - export type ResultForOptions | MutateOptions> = LazyType, OptionWithFallback & ErrorPolicy>>; + export type ResultForOptions | MutateOptions> = LazyType, OptionWithFallback & ErrorPolicy>>; export interface Signature extends Signatures.Evaluated { } // (undocumented) export namespace Signatures { // (undocumented) export interface Classic { - (options: ApolloClient.MutateOptions & { + (options: ApolloClient.MutateOptions & { errorPolicy?: TErrorPolicy; }): Promise, TErrorPolicy>>; // @deprecated (undocumented) - (options: ApolloClient.MutateOptions & (TErrorPolicy extends undefined ? {} : { + (options: ApolloClient.MutateOptions & (TErrorPolicy extends undefined ? {} : { errorPolicy: TErrorPolicy; })): Promise, TErrorPolicy>>; } @@ -297,18 +297,18 @@ export namespace ApolloClient { export type Evaluated = SignatureStyle extends "classic" ? Classic : Modern; // (undocumented) export interface Modern { - , NoInfer, TCache> & VariablesOption, NoInfer, Cache_2.Implementation> & VariablesOption]?: never; }>>(options: TOptions & { mutation: TypedDocumentNode; - }): Promise>; + }): Promise>; } } } // Warning: (ae-forgotten-export) The symbol "VariablesOption" needs to be exported by the entry point index.d.ts // // (undocumented) - export type MutateOptions = { + export type MutateOptions = { optimisticResponse?: Unmasked> | ((vars: TVariables, { IGNORE }: { IGNORE: IgnoreModifier; }) => Unmasked> | IgnoreModifier); @@ -355,7 +355,7 @@ export namespace ApolloClient { // (undocumented) export interface Options extends InternalTypes.DefaultOptionsParentObject { assumeImmutableResults?: boolean; - cache: ApolloCache; + cache: Cache_2.Implementation; // Warning: (ae-forgotten-export) The symbol "ClientAwarenessLink" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -445,7 +445,7 @@ export namespace ApolloClient { export type ReadFragmentOptions = Base.ReadFragmentOptions & VariablesOption & Cache_2.CacheIdentifierOption; // (undocumented) export type ReadQueryOptions = Base.ReadQueryOptions & VariablesOption; - export interface RefetchQueriesOptions { + export interface RefetchQueriesOptions { include?: RefetchQueriesInclude; onQueryUpdated?: OnQueryUpdated | null; optimistic?: boolean; @@ -508,7 +508,7 @@ export class ApolloClient { // (undocumented) __requestRaw(request: ApolloLink.Request): Observable>; // (undocumented) - cache: ApolloCache; + cache: Cache_2.Implementation; clearStore(): Promise; // (undocumented) get defaultContext(): Partial; @@ -547,7 +547,7 @@ export class ApolloClient { // @deprecated reFetchObservableQueries: (includeStandby?: boolean) => Promise[]>; refetchObservableQueries(includeStandby?: boolean): Promise[]>; - refetchQueries>>(options: ApolloClient.RefetchQueriesOptions): ApolloClient.RefetchQueriesResult; + refetchQueries>>(options: ApolloClient.RefetchQueriesOptions): ApolloClient.RefetchQueriesResult; resetStore(): Promise[] | null>; restore(serializedState: unknown): ApolloCache; setLink(newLink: ApolloLink): void; @@ -746,7 +746,7 @@ export const build: "source" | "esm" | "cjs"; // @public (undocumented) namespace Cache_2 { // (undocumented) - interface BatchOptions { + interface BatchOptions { onWatchUpdated?: (this: TCache, watch: Cache_2.WatchOptions, diff: Cache_2.DiffResult, lastDiff?: Cache_2.DiffResult | undefined) => any; optimistic?: string | boolean; removeOptimistic?: string; @@ -787,6 +787,10 @@ namespace Cache_2 { id?: string; } // (undocumented) + type Implementation = TypeOverrides extends { + cache: infer TCache; + } ? TCache extends ApolloCache ? TCache : "The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type." : ApolloCache; + // (undocumented) interface ModifyOptions = Record> { // (undocumented) broadcast?: boolean; @@ -1962,7 +1966,7 @@ export type MutateResult = ApolloClient.MutateResult; export type MutationFetchPolicy = Extract; // @public @deprecated (undocumented) -export type MutationOptions = ApolloClient.MutateOptions; +export type MutationOptions = ApolloClient.MutateOptions; // @public (undocumented) export type MutationQueryReducer = (previousResult: Record, options: { @@ -1991,7 +1995,7 @@ interface MutationStoreValue { } // @public (undocumented) -export type MutationUpdaterFunction = (cache: TCache, result: FormattedExecutionResult>, options: { +export type MutationUpdaterFunction = (cache: TCache, result: FormattedExecutionResult>, options: { context?: DefaultContext; variables?: TVariables; }) => void; @@ -2473,7 +2477,7 @@ class QueryManager { // (undocumented) maskOperation(options: MaskOperationOptions): MaybeMasked; // (undocumented) - mutate({ mutation, variables, optimisticResponse, updateQueries, refetchQueries, awaitRefetchQueries, update: updateWithProxyFn, onQueryUpdated, fetchPolicy, errorPolicy, keepRootFields, context, }: ApolloClient.MutateOptions & { + mutate({ mutation, variables, optimisticResponse, updateQueries, refetchQueries, awaitRefetchQueries, update: updateWithProxyFn, onQueryUpdated, fetchPolicy, errorPolicy, keepRootFields, context, }: ApolloClient.MutateOptions & { errorPolicy: ErrorPolicy; fetchPolicy: MutationFetchPolicy; }): Promise>>; @@ -2488,7 +2492,7 @@ class QueryManager { // (undocumented) refetchObservableQueries(includeStandby?: boolean): Promise[]>; // (undocumented) - refetchQueries({ updateCache, include, optimistic, removeOptimistic, onQueryUpdated, }: InternalRefetchQueriesOptions): InternalRefetchQueriesMap; + refetchQueries({ updateCache, include, optimistic, removeOptimistic, onQueryUpdated, }: InternalRefetchQueriesOptions): InternalRefetchQueriesMap; // (undocumented) readonly ssrMode: boolean; // (undocumented) @@ -2689,7 +2693,7 @@ export type RefetchQueriesInclude = RefetchQueryDescriptor[] | RefetchQueriesInc type RefetchQueriesIncludeShorthand = "all" | "active"; // @public @deprecated (undocumented) -export type RefetchQueriesOptions = ApolloClient.RefetchQueriesOptions; +export type RefetchQueriesOptions = ApolloClient.RefetchQueriesOptions; // @public (undocumented) export type RefetchQueriesPromiseResults = IsAny extends true ? any[] : TResult extends boolean ? ApolloClient.QueryResult[] : TResult extends PromiseLike ? U[] : TResult[]; @@ -3070,7 +3074,7 @@ interface WriteContext extends ReadMergeModifyContext { // src/cache/inmemory/policies.ts:173:3 - (ae-forgotten-export) The symbol "KeyArgsFunction" needs to be exported by the entry point index.d.ts // src/cache/inmemory/types.ts:135:3 - (ae-forgotten-export) The symbol "KeyFieldsFunction" needs to be exported by the entry point index.d.ts // src/core/ApolloClient.ts:201:5 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts -// src/core/ApolloClient.ts:633:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts +// src/core/ApolloClient.ts:635:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts // src/core/ObservableQuery.ts:375:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts // src/core/QueryManager.ts:195:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts // src/local-state/LocalState.ts:149:5 - (ae-forgotten-export) The symbol "LocalState" needs to be exported by the entry point index.d.ts diff --git a/.changeset/fuzzy-hairs-tie.md b/.changeset/fuzzy-hairs-tie.md new file mode 100644 index 00000000000..ab9769f89ab --- /dev/null +++ b/.changeset/fuzzy-hairs-tie.md @@ -0,0 +1,34 @@ +--- +"@apollo/client": minor +--- + +Add the ability to define the cache type for the client. `client.cache` currently returns `ApolloCache` as the cache type regardless of what cache you've provided to `ApolloClient`. + +Declare the cache type using the `cache` property in the `TypeOverrides` interface to set the cache implementation used for the client. + +```ts +// apollo.d.ts +import type { InMemoryCache } from "@apollo/client"; + +declare module "@apollo/client" { + export interface TypeOverrides { + cache: InMemoryCache; + } +} +``` + +Now anywhere `cache` is accessible, the type is the declared cache type: + +```ts +client.cache; +// ^? InMemoryCache + +client.mutate({ + update: (cache) => { + // ^? InMemoryCache + }, +}); +``` + +> [!NOTE] +> Setting a cache type enforces that cache type in the `cache` option for the `ApolloClient` constructor. diff --git a/integration-tests/type-tests/cacheOverride/classicSignature/index.ts b/integration-tests/type-tests/cacheOverride/classicSignature/index.ts new file mode 100644 index 00000000000..766e62259c2 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/classicSignature/index.ts @@ -0,0 +1,360 @@ +import { + ApolloClient, + ApolloLink, + Cache, + TypedDocumentNode, + MutationUpdaterFunction, + ApolloCache, + InMemoryCache, +} from "@apollo/client"; +import { + useApolloClient, + useLazyQuery, + useMutation, + useQuery, + useSuspenseQuery, +} from "@apollo/client/react"; +import { expectTypeOf } from "expect-type"; +import { test, TestCache } from "../shared/index.js"; + +declare module "@apollo/client" { + export interface TypeOverrides { + cache: TestCache; + signatureStyle: "classic"; + } +} + +type Data = { foo: string }; +type Variables = { bar?: string }; + +declare const mutation: TypedDocumentNode; +declare const query: TypedDocumentNode; + +test("ApolloClient constructor", () => { + { + const client = new ApolloClient({ + // @ts-expect-error cache isn't TestCache + cache: new InMemoryCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("client.mutate", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + // @ts-expect-error wrong TCache subtype + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); +}); + +test("client.refetchQueries", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + // @ts-expect-error wrong TCache subtype + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); +}); + +test("cache.batch", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.cache.batch({ + update(cache) { + expectTypeOf(cache).toEqualTypeOf(); + }, + onWatchUpdated() { + expectTypeOf(this).toEqualTypeOf(); + }, + }); +}); + +test("useApolloClient", () => { + const client = useApolloClient(); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useLazyQuery", () => { + const [, { client }] = useLazyQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useMutation", () => { + { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + // @ts-expect-error wrong TCache subtype + const [mutate, { client }] = useMutation( + mutation, + { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + } + ); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const [mutate, { client }] = useMutation( + mutation, + { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + } + ); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const [mutate, { client }] = useMutation< + Data, + Variables, + Cache.Implementation + >(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("useQuery", () => { + const { client } = useQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useSuspenseQuery", () => { + const { client } = useSuspenseQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); diff --git a/integration-tests/type-tests/cacheOverride/classicSignature/tsconfig.json b/integration-tests/type-tests/cacheOverride/classicSignature/tsconfig.json new file mode 100644 index 00000000000..fc7c8ff3c52 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/classicSignature/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true + }, + "references": [ + { + "path": "../../tsconfig.src.json" + }, + { + "path": "../shared/tsconfig.json" + } + ] +} diff --git a/integration-tests/type-tests/cacheOverride/defaults/index.ts b/integration-tests/type-tests/cacheOverride/defaults/index.ts new file mode 100644 index 00000000000..98bf267fb81 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/defaults/index.ts @@ -0,0 +1,300 @@ +import { + ApolloCache, + ApolloClient, + ApolloLink, + InMemoryCache, + MutationUpdaterFunction, + TypedDocumentNode, +} from "@apollo/client"; +import { + useApolloClient, + useLazyQuery, + useMutation, + useQuery, + useSuspenseQuery, +} from "@apollo/client/react"; +import { expectTypeOf } from "expect-type"; +import { test, TestCache } from "../shared/index.js"; + +type Data = { foo: string }; +type Variables = { bar?: string }; + +declare const mutation: TypedDocumentNode; +declare const query: TypedDocumentNode; + +test("ApolloClient constructor", () => { + { + const client = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("client.mutate", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); +}); + +test("client.refetchQueries", () => { + { + const client = new ApolloClient({ + cache: new InMemoryCache(), + link: ApolloLink.empty(), + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + } + + { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + } +}); + +test("cache.batch", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.cache.batch({ + update(cache) { + expectTypeOf(cache).toEqualTypeOf(); + }, + onWatchUpdated() { + expectTypeOf(this).toEqualTypeOf(); + }, + }); +}); + +test("useApolloClient", () => { + const client = useApolloClient(); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useLazyQuery", () => { + const [, { client }] = useLazyQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useMutation", () => { + { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + // Ensure TCache can override any subtype of ApolloCache + { + const [mutate, { client }] = useMutation( + mutation, + { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + } + ); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + // Ensure TCache can override any subtype of ApolloCache + { + const [mutate, { client }] = useMutation( + mutation, + { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + } + ); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("useQuery", () => { + const { client } = useQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useSuspenseQuery", () => { + const { client } = useSuspenseQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); diff --git a/integration-tests/type-tests/cacheOverride/defaults/tsconfig.json b/integration-tests/type-tests/cacheOverride/defaults/tsconfig.json new file mode 100644 index 00000000000..fc7c8ff3c52 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/defaults/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true + }, + "references": [ + { + "path": "../../tsconfig.src.json" + }, + { + "path": "../shared/tsconfig.json" + } + ] +} diff --git a/integration-tests/type-tests/cacheOverride/invalid/index.ts b/integration-tests/type-tests/cacheOverride/invalid/index.ts new file mode 100644 index 00000000000..8ec4588e08e --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/invalid/index.ts @@ -0,0 +1,288 @@ +import { + ApolloCache, + ApolloClient, + ApolloLink, + InMemoryCache, + MutationUpdaterFunction, + TypedDocumentNode, +} from "@apollo/client"; +import { + useApolloClient, + useLazyQuery, + useMutation, + useQuery, + useSuspenseQuery, +} from "@apollo/client/react"; +import { expectTypeOf } from "expect-type"; +import { test, TestCache } from "../shared/index.js"; + +declare module "@apollo/client" { + export interface TypeOverrides { + cache: number; + } +} +type Data = { foo: string }; +type Variables = { bar?: string }; + +declare const mutation: TypedDocumentNode; +declare const query: TypedDocumentNode; + +type WrongCacheMessage = + "The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type."; + +test("ApolloClient constructor", () => { + { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: new InMemoryCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: 123, + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("client.mutate", () => { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); +}); + +test("client.refetchQueries", () => { + { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: new InMemoryCache(), + link: ApolloLink.empty(), + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + } + + { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + } +}); + +test("cache.batch", () => { + const client = new ApolloClient({ + // @ts-expect-error The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type. + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + // @ts-expect-error property 'batch' doesn't exist in 'The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type.' + client.cache.batch({ + // @ts-expect-error inferred any + update(cache) { + expectTypeOf(cache).toEqualTypeOf(); + }, + onWatchUpdated() { + expectTypeOf(this).toEqualTypeOf(); + }, + }); +}); + +test("useApolloClient", () => { + const client = useApolloClient(); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useLazyQuery", () => { + const [, { client }] = useLazyQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useMutation", () => { + { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const [mutate, { client }] = useMutation< + Data, + Variables, + WrongCacheMessage + >(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("useQuery", () => { + const { client } = useQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useSuspenseQuery", () => { + const { client } = useSuspenseQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); diff --git a/integration-tests/type-tests/cacheOverride/invalid/tsconfig.json b/integration-tests/type-tests/cacheOverride/invalid/tsconfig.json new file mode 100644 index 00000000000..fc7c8ff3c52 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/invalid/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true + }, + "references": [ + { + "path": "../../tsconfig.src.json" + }, + { + "path": "../shared/tsconfig.json" + } + ] +} diff --git a/integration-tests/type-tests/cacheOverride/modernSignature/index.ts b/integration-tests/type-tests/cacheOverride/modernSignature/index.ts new file mode 100644 index 00000000000..941c62640d0 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/modernSignature/index.ts @@ -0,0 +1,174 @@ +import { + ApolloClient, + ApolloLink, + Cache, + TypedDocumentNode, + MutationUpdaterFunction, + ApolloCache, + InMemoryCache, +} from "@apollo/client"; +import { + useApolloClient, + useLazyQuery, + useMutation, + useQuery, + useSuspenseQuery, +} from "@apollo/client/react"; +import { expectTypeOf } from "expect-type"; +import { test, TestCache } from "../shared/index.js"; + +declare module "@apollo/client" { + export interface TypeOverrides { + cache: TestCache; + signatureStyle: "modern"; + } +} + +type Data = { foo: string }; +type Variables = { bar?: string }; + +declare const mutation: TypedDocumentNode; +declare const query: TypedDocumentNode; + +test("ApolloClient constructor", () => { + { + const client = new ApolloClient({ + // @ts-expect-error cache isn't TestCache + cache: new InMemoryCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } + + { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + expectTypeOf(client.cache).toEqualTypeOf(); + } +}); + +test("client.mutate", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.mutate({ + mutation, + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); +}); + +test("client.refetchQueries", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + // @ts-expect-error wrong TCache subtype + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); + + client.refetchQueries({ + updateCache: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + }); +}); + +test("cache.batch", () => { + const client = new ApolloClient({ + cache: new TestCache(), + link: ApolloLink.empty(), + }); + + client.cache.batch({ + update(cache) { + expectTypeOf(cache).toEqualTypeOf(); + }, + onWatchUpdated() { + expectTypeOf(this).toEqualTypeOf(); + }, + }); +}); + +test("useApolloClient", () => { + const client = useApolloClient(); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useLazyQuery", () => { + const [, { client }] = useLazyQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useMutation", () => { + const [mutate, { client }] = useMutation(mutation, { + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + mutate({ + update: (cache) => { + expectTypeOf(cache).toEqualTypeOf(); + }, + onCompleted: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + onError: (_, options) => { + expectTypeOf(options!.update!).toEqualTypeOf< + MutationUpdaterFunction + >; + }, + }); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useQuery", () => { + const { client } = useQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); + +test("useSuspenseQuery", () => { + const { client } = useSuspenseQuery(query); + + expectTypeOf(client.cache).toEqualTypeOf(); +}); diff --git a/integration-tests/type-tests/cacheOverride/modernSignature/tsconfig.json b/integration-tests/type-tests/cacheOverride/modernSignature/tsconfig.json new file mode 100644 index 00000000000..fc7c8ff3c52 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/modernSignature/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true + }, + "references": [ + { + "path": "../../tsconfig.src.json" + }, + { + "path": "../shared/tsconfig.json" + } + ] +} diff --git a/integration-tests/type-tests/cacheOverride/shared/index.ts b/integration-tests/type-tests/cacheOverride/shared/index.ts new file mode 100644 index 00000000000..ade588b5ed3 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/shared/index.ts @@ -0,0 +1,46 @@ +import { + ApolloCache, + Cache, + OperationVariables, + Reference, + Transaction, +} from "@apollo/client"; +import { FragmentDefinitionNode, InlineFragmentNode } from "graphql"; + +export declare function test(description: string, fn: () => void): void; + +export declare class TestCache extends ApolloCache { + public read< + TData = unknown, + TVariables extends OperationVariables = OperationVariables, + >(query: Cache.ReadOptions): TData | null; + public write< + TData = unknown, + TVariables extends OperationVariables = OperationVariables, + >(write: Cache.WriteOptions): Reference | undefined; + public diff< + TData = unknown, + TVariables extends OperationVariables = OperationVariables, + >(query: Cache.DiffOptions): Cache.DiffResult; + public watch< + TData = unknown, + TVariables extends OperationVariables = OperationVariables, + >(watch: Cache.WatchOptions): () => void; + public reset(options?: Cache.ResetOptions): Promise; + public evict(options: Cache.EvictOptions): boolean; + public restore(serializedState: unknown): this; + public extract(optimistic?: boolean): unknown; + public removeOptimistic(id: string): void; + public fragmentMatches( + fragment: InlineFragmentNode | FragmentDefinitionNode, + typename: string + ): boolean; + public performTransaction( + transaction: Transaction, + optimisticId?: string | null + ): void; + + // a custom method to structurally distinguish this cache + // impl from base cache or InMemoryCache + public testCacheOnly(): boolean; +} diff --git a/integration-tests/type-tests/cacheOverride/shared/tsconfig.json b/integration-tests/type-tests/cacheOverride/shared/tsconfig.json new file mode 100644 index 00000000000..6e0a5593323 --- /dev/null +++ b/integration-tests/type-tests/cacheOverride/shared/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true + }, + "references": [ + { + "path": "../../tsconfig.src.json" + } + ] +} diff --git a/integration-tests/type-tests/tsconfig.json b/integration-tests/type-tests/tsconfig.json index 404e60e00c4..ed97b631388 100644 --- a/integration-tests/type-tests/tsconfig.json +++ b/integration-tests/type-tests/tsconfig.json @@ -3,6 +3,21 @@ { "path": "./tsconfig.src.json" }, + { + "path": "./cacheOverride/classicSignature/tsconfig.json" + }, + { + "path": "./cacheOverride/defaults/tsconfig.json" + }, + { + "path": "./cacheOverride/invalid/tsconfig.json" + }, + { + "path": "./cacheOverride/modernSignature/tsconfig.json" + }, + { + "path": "./cacheOverride/shared/tsconfig.json" + }, { "path": "./defaultOptions/shared/tsconfig.json" }, diff --git a/src/cache/core/types/Cache.ts b/src/cache/core/types/Cache.ts index 9b2f085222f..c126c09035a 100644 --- a/src/cache/core/types/Cache.ts +++ b/src/cache/core/types/Cache.ts @@ -3,6 +3,7 @@ import type { DocumentNode, OperationVariables, TypedDocumentNode, + TypeOverrides, } from "@apollo/client"; import type { Unmasked } from "@apollo/client/masking"; import type { ExtensionsWithStreamInfo } from "@apollo/client/utilities/internal"; @@ -20,6 +21,13 @@ export declare namespace Cache { lastDiff?: Cache.DiffResult ) => void; + export type Implementation = + TypeOverrides extends { cache: infer TCache } ? + TCache extends ApolloCache ? + TCache + : "The cache type declared in TypeOverrides does not extend `ApolloCache` and cannot be used with Apollo Client. See https://www.apollographql.com/docs/react/data/typescript#declaring-the-cache-type." + : ApolloCache; + export interface ReadOptions< TData = unknown, TVariables extends OperationVariables = OperationVariables, @@ -128,7 +136,7 @@ export declare namespace Cache { } export interface BatchOptions< - TCache extends ApolloCache, + TCache extends Cache.Implementation, TUpdateResult = void, > { /** diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index ff9e9d77211..b92a7701d39 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -106,7 +106,7 @@ export declare namespace ApolloClient { * * For more information, see [Configuring the cache](https://www.apollographql.com/docs/react/caching/cache-configuration/). */ - cache: ApolloCache; + cache: Cache.Implementation; /** * The time interval (in milliseconds) before Apollo Client force-fetches queries after a server-side render. * @@ -195,7 +195,7 @@ export declare namespace ApolloClient { export type MutateOptions< TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, > = { /** {@inheritDoc @apollo/client!MutationOptionsDocumentation#optimisticResponse:member} */ optimisticResponse?: @@ -247,7 +247,7 @@ export declare namespace ApolloClient { export type ResultForOptions< TData, TVariables extends OperationVariables, - TCache extends ApolloCache, + TCache extends Cache.Implementation, TOptions extends | Record | MutateOptions, @@ -270,7 +270,7 @@ export declare namespace ApolloClient { options: ApolloClient.MutateOptions< TData, TVariables, - ApolloCache + Cache.Implementation > & { errorPolicy?: TErrorPolicy } ): Promise, TErrorPolicy>>; @@ -283,7 +283,7 @@ export declare namespace ApolloClient { < TData, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TErrorPolicy extends ErrorPolicy | undefined = undefined, >( options: ApolloClient.MutateOptions & @@ -296,12 +296,11 @@ export declare namespace ApolloClient { < TData, TVariables extends OperationVariables, - TCache extends ApolloCache, // this overload should never be manually defined, it should always be inferred TOptions extends ApolloClient.MutateOptions< NoInfer, NoInfer, - TCache + Cache.Implementation > & VariablesOption< TVariables & { @@ -319,7 +318,7 @@ export declare namespace ApolloClient { ApolloClient.mutate.ResultForOptions< TData, TVariables, - TCache, + Cache.Implementation, TOptions > >; @@ -512,7 +511,10 @@ export declare namespace ApolloClient { /** * Options object for the `client.refetchQueries` method. */ - export interface RefetchQueriesOptions { + export interface RefetchQueriesOptions< + TCache extends Cache.Implementation, + TResult, + > { /** * Optional function that updates cached fields to trigger refetches of queries that include those fields. */ @@ -979,7 +981,7 @@ export declare namespace ApolloClient { function mutate< TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, >( options: ApolloClient.MutateOptions ): Promise>>; @@ -994,7 +996,7 @@ export declare namespace ApolloClient { */ export class ApolloClient { public link: ApolloLink; - public cache: ApolloCache; + public cache: Cache.Implementation; /** * @deprecated `disableNetworkFetches` has been renamed to `prioritizeCacheValues`. */ @@ -1399,7 +1401,7 @@ export class ApolloClient { public mutate: ApolloClient.mutate.Signature = < TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, >( options: ApolloClient.MutateOptions ): Promise>> => { @@ -1848,13 +1850,16 @@ export class ApolloClient { * active queries. */ public refetchQueries< - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TResult = Promise>, >( options: ApolloClient.RefetchQueriesOptions ): ApolloClient.RefetchQueriesResult { const map = this.queryManager.refetchQueries( - options as ApolloClient.RefetchQueriesOptions + options as ApolloClient.RefetchQueriesOptions< + Cache.Implementation, + TResult + > ); const queries: ObservableQuery[] = []; const results: InternalRefetchQueriesResult[] = []; diff --git a/src/core/QueryManager.ts b/src/core/QueryManager.ts index 06f31042838..334a2824ecf 100644 --- a/src/core/QueryManager.ts +++ b/src/core/QueryManager.ts @@ -24,7 +24,7 @@ import { tap, } from "rxjs"; -import type { ApolloCache, Cache } from "@apollo/client/cache"; +import type { Cache } from "@apollo/client/cache"; import { canonicalStringify } from "@apollo/client/cache"; import { CombinedGraphQLErrors, @@ -268,7 +268,7 @@ export class QueryManager { public async mutate< TData, TVariables extends OperationVariables, - TCache extends ApolloCache, + TCache extends Cache.Implementation, >({ mutation, variables, @@ -1329,7 +1329,7 @@ export class QueryManager { removeOptimistic = optimistic ? makeUniqueId("refetchQueries") : void 0, onQueryUpdated, }: InternalRefetchQueriesOptions< - ApolloCache, + Cache.Implementation, TResult >): InternalRefetchQueriesMap { const includedQueriesByOq = new Map< diff --git a/src/core/deprecated.ts b/src/core/deprecated.ts index 31b63f916ef..ca6fb624aec 100644 --- a/src/core/deprecated.ts +++ b/src/core/deprecated.ts @@ -1,4 +1,4 @@ -import type { ApolloCache } from "@apollo/client/cache"; +import type { Cache } from "@apollo/client/cache"; import type { ApolloClient } from "./ApolloClient.js"; import type { ObservableQuery } from "./ObservableQuery.js"; @@ -23,7 +23,7 @@ export type DevtoolsOptions = ApolloClient.DevtoolsOptions; export type MutationOptions< TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, > = ApolloClient.MutateOptions; /** @deprecated Use `ApolloClient.MutateResult` instead */ @@ -38,7 +38,7 @@ export type QueryOptions< /** @deprecated Use `ApolloClient.RefetchQueriesOptions` instead */ export type RefetchQueriesOptions< - TCache extends ApolloCache, + TCache extends Cache.Implementation, TResult, > = ApolloClient.RefetchQueriesOptions; diff --git a/src/core/types.ts b/src/core/types.ts index 5f32a1b0912..f6696ed243b 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -361,7 +361,7 @@ export type MutationQueryReducersMap = { export type MutationUpdaterFunction< TData, TVariables extends OperationVariables, - TCache extends ApolloCache, + TCache extends Cache.Implementation, > = ( cache: TCache, result: FormattedExecutionResult>, diff --git a/src/declarations.d.ts b/src/declarations.d.ts index d47b1b19f39..4c5fe1ae53b 100644 --- a/src/declarations.d.ts +++ b/src/declarations.d.ts @@ -1,4 +1,4 @@ -import type { InternalTypes } from "@apollo/client"; +import type { ApolloCache, InternalTypes } from "@apollo/client"; declare module "@apollo/client" { // in our own codebase, we have to account for all possible `defaultOptions`s @@ -9,4 +9,8 @@ declare module "@apollo/client" { interface Mutate {} } } + + export interface TypeOverrides { + cache: ApolloCache; + } } diff --git a/src/react/hooks/useMutation.ts b/src/react/hooks/useMutation.ts index 64a706a705d..4c5089c956b 100644 --- a/src/react/hooks/useMutation.ts +++ b/src/react/hooks/useMutation.ts @@ -3,7 +3,6 @@ import { equal } from "@wry/equality"; import * as React from "react"; import type { - ApolloCache, ApolloClient, DefaultContext, DocumentNode, @@ -19,7 +18,7 @@ import type { OperationVariables, Unmasked, } from "@apollo/client"; -import type { IgnoreModifier } from "@apollo/client/cache"; +import type { Cache, IgnoreModifier } from "@apollo/client/cache"; import type { LazyType, NoInfer, @@ -66,7 +65,7 @@ export declare namespace useMutation { export interface Options< TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TConfiguredVariables extends Partial = Partial, > { /** {@inheritDoc @apollo/client!MutationOptionsDocumentation#optimisticResponse:member} */ @@ -207,7 +206,7 @@ export declare namespace useMutation { export type ResultTuple< TData, TVariables extends OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TErrorPolicy extends ErrorPolicy | undefined = undefined, > = [ mutate: MutationFunction, @@ -217,7 +216,7 @@ export declare namespace useMutation { export type MutationFunction< TData, TVariables extends OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TErrorPolicy extends ErrorPolicy | undefined = undefined, > = ( ...[options]: {} extends TVariables ? @@ -238,7 +237,7 @@ export declare namespace useMutation { export type MutationFunctionOptions< TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, > = Options & { /** * {@inheritDoc @apollo/client!MutationOptionsDocumentation#context:member} @@ -258,7 +257,7 @@ export declare namespace useMutation { export type ResultForOptions< TData, TVariables extends OperationVariables, - TCache extends ApolloCache, + TCache extends Cache.Implementation, TOptions extends Record | Options, TErrorPolicy extends ErrorPolicy | undefined = undefined, > = LazyType< @@ -357,7 +356,7 @@ export declare namespace useMutation { options?: useMutation.Options< NoInfer, NoInfer, - ApolloCache, + Cache.Implementation, { [K in keyof TConfiguredVariables]: K extends keyof TVariables ? TConfiguredVariables[K] @@ -370,7 +369,7 @@ export declare namespace useMutation { ): useMutation.ResultTuple< TData, MakeRequiredVariablesOptional, - ApolloCache, + Cache.Implementation, TErrorPolicy >; @@ -383,7 +382,7 @@ export declare namespace useMutation { < TData, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TConfiguredVariables extends Partial = {}, TErrorPolicy extends ErrorPolicy | undefined = undefined, >( @@ -417,7 +416,6 @@ export declare namespace useMutation { < TData, TVariables extends OperationVariables, - TCache extends ApolloCache, // this overload should never be manually defined, it should always be inferred TOptions extends never, >( @@ -425,7 +423,7 @@ export declare namespace useMutation { ): useMutation.ResultForOptions< TData, TVariables, - TCache, + Cache.Implementation, Record >; @@ -433,12 +431,11 @@ export declare namespace useMutation { < TData, TVariables extends OperationVariables, - TCache extends ApolloCache, // this overload should never be manually defined, it should always be inferred TOptions extends useMutation.Options< NoInfer, NoInfer, - TCache + Cache.Implementation > & { variables?: { [K in Exclude< @@ -457,7 +454,7 @@ export declare namespace useMutation { ): useMutation.ResultForOptions< TData, TVariables, - TCache, + Cache.Implementation, TOptions, TErrorPolicy >; @@ -474,7 +471,7 @@ export declare namespace useMutation { export const useMutation: useMutation.Signature = function useMutation< TData = unknown, TVariables extends OperationVariables = OperationVariables, - TCache extends ApolloCache = ApolloCache, + TCache extends Cache.Implementation = Cache.Implementation, TConfiguredVariables extends Partial = {}, >( mutation: DocumentNode | TypedDocumentNode,