diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index 82d77d31257..734f8a760b8 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -14,6 +14,7 @@ import { ApolloQueryResult, OperationVariables, Resolvers, + Context, } from './types'; import { @@ -33,7 +34,7 @@ import { export interface DefaultOptions { watchQuery?: Partial>; query?: Partial>; - mutate?: Partial>; + mutate?: Partial>; } let hasSuggestedDevtools = false; @@ -57,13 +58,13 @@ export type ApolloClientOptions = { version?: string; }; -type OptionsUnion = +type OptionsUnion = | WatchQueryOptions | QueryOptions - | MutationOptions; + | MutationOptions; export function mergeOptions< - TOptions extends OptionsUnion + TOptions extends OptionsUnion >( defaults: Partial, options: TOptions, @@ -348,13 +349,13 @@ export class ApolloClient implements DataProxy { * * It takes options as an object with the following keys and values: */ - public mutate( - options: MutationOptions, + public mutate( + options: MutationOptions, ): Promise> { if (this.defaultOptions.mutate) { options = mergeOptions(this.defaultOptions.mutate, options); } - return this.queryManager.mutate(options); + return this.queryManager.mutate(options); } /** diff --git a/src/core/QueryManager.ts b/src/core/QueryManager.ts index 2924c46584b..099a62297bc 100644 --- a/src/core/QueryManager.ts +++ b/src/core/QueryManager.ts @@ -35,6 +35,7 @@ import { NetworkStatus, isNetworkRequestInFlight } from './networkStatus'; import { ApolloQueryResult, OperationVariables, + MutationUpdaterFunction, ReobserveQueryCallback, } from './types'; import { LocalState } from './LocalState'; @@ -55,6 +56,8 @@ interface MutationStoreValue { error: Error | null; } +type UpdateQueries = MutationOptions["updateQueries"]; + export class QueryManager { public cache: ApolloCache; public link: ApolloLink; @@ -128,7 +131,7 @@ export class QueryManager { this.fetchCancelFns.clear(); } - public async mutate({ + public async mutate({ mutation, variables, optimisticResponse, @@ -139,8 +142,8 @@ export class QueryManager { reobserveQuery, errorPolicy = 'none', fetchPolicy, - context = {}, - }: MutationOptions): Promise> { + context, + }: MutationOptions): Promise> { invariant( mutation, 'mutation option is required. You must specify your GraphQL document in the mutation option.', @@ -154,10 +157,10 @@ export class QueryManager { const mutationId = this.generateMutationId(); mutation = this.transform(mutation).document; - variables = this.getVariables(mutation, variables); + variables = this.getVariables(mutation, variables) as TVariables; if (this.transform(mutation).hasClientExports) { - variables = await this.localState.addExportedVariables(mutation, variables, context); + variables = await this.localState.addExportedVariables(mutation, variables, context) as TVariables; } const mutationStoreValue = @@ -170,11 +173,12 @@ export class QueryManager { } as MutationStoreValue); if (optimisticResponse) { - this.markMutationOptimistic(optimisticResponse, { + this.markMutationOptimistic(optimisticResponse, { mutationId, document: mutation, variables, errorPolicy, + context, updateQueries, update: updateWithProxyFn, }); @@ -213,17 +217,18 @@ export class QueryManager { storeResult = result; if (fetchPolicy !== 'no-cache') { + // Returning the result of markMutationResult here makes the + // mutation await any Promise that markMutationResult returns, + // since we are returning this Promise from the asyncMap mapping + // function. try { - // Returning the result of markMutationResult here makes the - // mutation await any Promise that markMutationResult returns, - // since we are returning this Promise from the asyncMap mapping - // function. - return self.markMutationResult({ + self.markMutationResult({ mutationId, result, document: mutation, variables, errorPolicy, + context, updateQueries, update: updateWithProxyFn, reobserveQuery, @@ -291,18 +296,16 @@ export class QueryManager { }); } - public markMutationResult( + public markMutationResult( mutation: { mutationId: string; result: FetchResult; document: DocumentNode; - variables?: OperationVariables; + variables?: TVariables; errorPolicy: ErrorPolicy; - updateQueries: MutationOptions["updateQueries"], - update?: ( - cache: ApolloCache, - result: FetchResult, - ) => void; + context?: TContext; + updateQueries: UpdateQueries; + update?: MutationUpdaterFunction; reobserveQuery?: ReobserveQueryCallback; }, cache = this.cache, @@ -364,7 +367,10 @@ export class QueryManager { // a write action. const { update } = mutation; if (update) { - update(c, mutation.result); + update(c as any, mutation.result, { + context: mutation.context, + variables: mutation.variables, + }); } }, @@ -389,18 +395,16 @@ export class QueryManager { return Promise.resolve(); } - public markMutationOptimistic( + public markMutationOptimistic( optimisticResponse: any, mutation: { mutationId: string; document: DocumentNode; - variables?: OperationVariables; + variables?: TVariables; errorPolicy: ErrorPolicy; - updateQueries: MutationOptions["updateQueries"], - update?: ( - cache: ApolloCache, - result: FetchResult, - ) => void; + context?: TContext; + updateQueries: UpdateQueries, + update?: MutationUpdaterFunction; }, ) { const data = typeof optimisticResponse === "function" @@ -409,7 +413,7 @@ export class QueryManager { return this.cache.recordOptimisticTransaction(cache => { try { - this.markMutationResult({ + this.markMutationResult({ ...mutation, result: { data }, }, cache); @@ -505,9 +509,9 @@ export class QueryManager { return transformCache.get(document)!; } - private getVariables( + private getVariables( document: DocumentNode, - variables?: OperationVariables, + variables?: TVariables, ): OperationVariables { return { ...this.transform(document).defaultVars, diff --git a/src/core/__tests__/QueryManager/index.ts b/src/core/__tests__/QueryManager/index.ts index a0fddec6f31..e55f231675d 100644 --- a/src/core/__tests__/QueryManager/index.ts +++ b/src/core/__tests__/QueryManager/index.ts @@ -5381,7 +5381,7 @@ describe('QueryManager', () => { describe('awaitRefetchQueries', () => { const awaitRefetchTest = - ({ awaitRefetchQueries, testQueryError = false }: MutationBaseOptions & { testQueryError?: boolean }) => + ({ awaitRefetchQueries, testQueryError = false }: MutationBaseOptions & { testQueryError?: boolean }) => new Promise((resolve, reject) => { const query = gql` query getAuthors($id: ID!) { @@ -5455,7 +5455,7 @@ describe('QueryManager', () => { { observable }, result => { expect(stripSymbols(result.data)).toEqual(queryData); - const mutateOptions: MutationOptions = { + const mutateOptions: MutationOptions = { mutation, refetchQueries: ['getAuthors'], }; diff --git a/src/core/index.ts b/src/core/index.ts index 6c005835443..a5fa0bb1c2d 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -21,7 +21,6 @@ export { ErrorPolicy, FetchMoreQueryOptions, SubscribeToMoreOptions, - MutationUpdaterFn, } from './watchQueryOptions'; export { NetworkStatus } from './networkStatus'; export * from './types'; diff --git a/src/core/types.ts b/src/core/types.ts index b90b84e35e0..aad96323efd 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -1,5 +1,6 @@ import { DocumentNode, GraphQLError } from 'graphql'; +import { ApolloCache } from '../cache'; import { FetchResult } from '../link/core'; import { ApolloError } from '../errors'; import { QueryInfo } from './QueryInfo'; @@ -10,6 +11,8 @@ import { Cache } from '../cache'; export { TypedDocumentNode } from '@graphql-typed-document-node/core'; +export type Context = Record; + export type QueryListener = (queryInfo: QueryInfo) => void; export type ReobserveQueryCallback = ( @@ -51,6 +54,14 @@ export type MutationQueryReducersMap = { [queryName: string]: MutationQueryReducer; }; +export type MutationUpdaterFunction = ( + cache: ApolloCache, + result: Omit, 'context'>, + options: { + context?: TContext, + variables?: TVariables, + }, +) => void; export interface Resolvers { [key: string]: { [ field: string ]: Resolver; diff --git a/src/core/watchQueryOptions.ts b/src/core/watchQueryOptions.ts index e6e2fd0efe9..5f6cf2cccdc 100644 --- a/src/core/watchQueryOptions.ts +++ b/src/core/watchQueryOptions.ts @@ -1,10 +1,15 @@ import { DocumentNode } from 'graphql'; import { TypedDocumentNode } from '@graphql-typed-document-node/core'; -import { ApolloCache } from '../cache'; import { FetchResult } from '../link/core'; -import { MutationQueryReducersMap, ReobserveQueryCallback } from './types'; -import { PureQueryOptions, OperationVariables } from './types'; +import { + Context, + MutationQueryReducersMap, + PureQueryOptions, + OperationVariables, + MutationUpdaterFunction, + ReobserveQueryCallback, +} from './types'; /** * fetchPolicy determines where the client may return a result from. The options are: @@ -179,8 +184,9 @@ export interface SubscriptionOptions; export interface MutationBaseOptions< - T = { [key: string]: any }, - TVariables = OperationVariables + T, + TVariables, + TContext, > { /** * An object that represents the result of this mutation that will be @@ -239,7 +245,7 @@ export interface MutationBaseOptions< * and you don't need to update the store, use the Promise returned from * `client.mutate` instead. */ - update?: MutationUpdaterFn; + update?: MutationUpdaterFunction; /** * A function that will be called for each ObservableQuery affected by @@ -260,9 +266,10 @@ export interface MutationBaseOptions< } export interface MutationOptions< - T = { [key: string]: any }, - TVariables = OperationVariables -> extends MutationBaseOptions { + T = any, + TVariables extends OperationVariables = OperationVariables, + TContext extends Context = Context, +> extends MutationBaseOptions { /** * A GraphQL document, often created with `gql` from the `graphql-tag` * package, that contains a single mutation inside of it. @@ -279,7 +286,7 @@ export interface MutationOptions< * [`query` `context` option](https://www.apollographql.com/docs/react/api/apollo-client#ApolloClient.query)) * when the query is first initialized/run. */ - context?: any; + context?: TContext; /** * Specifies the {@link FetchPolicy} to be used for this query. Mutations only @@ -289,9 +296,3 @@ export interface MutationOptions< */ fetchPolicy?: Extract; } - -// Add a level of indirection for `typedoc`. -export type MutationUpdaterFn = ( - cache: ApolloCache, - mutationResult: FetchResult, -) => void; diff --git a/src/react/components/types.ts b/src/react/components/types.ts index 83dea55043f..6f602afb593 100644 --- a/src/react/components/types.ts +++ b/src/react/components/types.ts @@ -1,7 +1,7 @@ import { DocumentNode } from 'graphql'; import { TypedDocumentNode } from '@graphql-typed-document-node/core'; -import { OperationVariables } from '../../core'; +import { OperationVariables, Context } from '../../core'; import { QueryFunctionOptions, QueryResult, @@ -22,11 +22,12 @@ export interface QueryComponentOptions< export interface MutationComponentOptions< TData = any, - TVariables = OperationVariables -> extends BaseMutationOptions { + TVariables = OperationVariables, + TContext = Context, +> extends BaseMutationOptions { mutation: DocumentNode | TypedDocumentNode; children: ( - mutateFunction: MutationFunction, + mutateFunction: MutationFunction, result: MutationResult ) => JSX.Element | null; } diff --git a/src/react/data/MutationData.ts b/src/react/data/MutationData.ts index 209cd8be6ac..5d8e4d0c98d 100644 --- a/src/react/data/MutationData.ts +++ b/src/react/data/MutationData.ts @@ -9,15 +9,16 @@ import { MutationResult, } from '../types/types'; import { OperationData } from './OperationData'; -import { OperationVariables, MutationOptions, mergeOptions } from '../../core'; +import { MutationOptions, mergeOptions } from '../../core'; import { FetchResult } from '../../link/core'; type MutationResultWithoutClient = Omit, 'client'>; export class MutationData< - TData = any, - TVariables = OperationVariables -> extends OperationData> { + TData, + TVariables, + TContext, +> extends OperationData> { private mostRecentMutationId: number; private result: MutationResultWithoutClient; private previousResult?: MutationResultWithoutClient; @@ -29,7 +30,7 @@ export class MutationData< result, setResult }: { - options: MutationDataOptions; + options: MutationDataOptions; context: any; result: MutationResultWithoutClient; setResult: (result: MutationResultWithoutClient) => any; @@ -41,13 +42,13 @@ export class MutationData< this.mostRecentMutationId = 0; } - public execute(result: MutationResultWithoutClient): MutationTuple { + public execute(result: MutationResultWithoutClient): MutationTuple { this.isMounted = true; this.verifyDocumentType(this.getOptions().mutation, DocumentType.Mutation); return [ this.runMutation, { ...result, client: this.refreshClient().client } - ] as MutationTuple; + ] as MutationTuple; } public afterExecute() { @@ -62,8 +63,9 @@ export class MutationData< private runMutation = ( mutationFunctionOptions: MutationFunctionOptions< TData, - TVariables - > = {} as MutationFunctionOptions + TVariables, + TContext + > = {} as MutationFunctionOptions ) => { this.onMutationStart(); const mutationId = this.generateNewMutationId(); @@ -80,12 +82,12 @@ export class MutationData< }; private mutate( - options: MutationFunctionOptions + options: MutationFunctionOptions ) { return this.refreshClient().client.mutate( mergeOptions( this.getOptions(), - options as MutationOptions, + options as MutationOptions, ), ); } diff --git a/src/react/hoc/__tests__/mutations/queries.test.tsx b/src/react/hoc/__tests__/mutations/queries.test.tsx index 1c32f5e89f6..40a80d31254 100644 --- a/src/react/hoc/__tests__/mutations/queries.test.tsx +++ b/src/react/hoc/__tests__/mutations/queries.test.tsx @@ -3,7 +3,7 @@ import { render, wait } from '@testing-library/react'; import gql from 'graphql-tag'; import { DocumentNode } from 'graphql'; -import { ApolloClient, MutationUpdaterFn } from '../../../../core'; +import { ApolloClient, MutationUpdaterFunction } from '../../../../core'; import { ApolloProvider } from '../../../context'; import { InMemoryCache as Cache } from '../../../../cache'; import { @@ -131,7 +131,11 @@ describe('graphql(mutation) query integration', () => { }; } - const update: MutationUpdaterFn = (proxy, result) => { + const update: MutationUpdaterFunction< + MutationData, + Record, + Record + > = (proxy, result) => { const data = JSON.parse( JSON.stringify(proxy.readQuery({ query })) ); diff --git a/src/react/hoc/__tests__/mutations/recycled-queries.test.tsx b/src/react/hoc/__tests__/mutations/recycled-queries.test.tsx index 53147256128..50537f504c0 100644 --- a/src/react/hoc/__tests__/mutations/recycled-queries.test.tsx +++ b/src/react/hoc/__tests__/mutations/recycled-queries.test.tsx @@ -3,7 +3,7 @@ import { render, wait } from '@testing-library/react'; import gql from 'graphql-tag'; import { DocumentNode } from 'graphql'; -import { ApolloClient, MutationUpdaterFn } from '../../../../core'; +import { ApolloClient, MutationUpdaterFunction } from '../../../../core'; import { ApolloProvider } from '../../../context'; import { InMemoryCache as Cache } from '../../../../cache'; import { MutationFunction } from '../../../types/types'; @@ -74,7 +74,11 @@ describe('graphql(mutation) update queries', () => { type MutationData = typeof mutationData; let todoUpdateQueryCount = 0; - const update: MutationUpdaterFn = (proxy, result) => { + const update: MutationUpdaterFunction< + MutationData, + Record, + Record + > = (proxy, result) => { todoUpdateQueryCount++; const data = JSON.parse( JSON.stringify( diff --git a/src/react/hoc/mutation-hoc.tsx b/src/react/hoc/mutation-hoc.tsx index 6f81396d664..354a332787f 100644 --- a/src/react/hoc/mutation-hoc.tsx +++ b/src/react/hoc/mutation-hoc.tsx @@ -3,6 +3,7 @@ import { DocumentNode } from 'graphql'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { parser } from '../parser'; +import { Context } from '../../core/types'; import { BaseMutationOptions, MutationFunction, @@ -20,9 +21,10 @@ import { OperationOption, OptionProps, MutateProps } from './types'; export function withMutation< TProps extends TGraphQLVariables | {} = {}, - TData = {}, + TData extends Record = {}, TGraphQLVariables = {}, - TChildProps = MutateProps + TChildProps = MutateProps, + TContext = Context, >( document: DocumentNode, operationOptions: OperationOption< @@ -41,9 +43,9 @@ export function withMutation< alias = 'Apollo' } = operationOptions; - let mapPropsToOptions = options as (props: any) => BaseMutationOptions; + let mapPropsToOptions = options as (props: any) => BaseMutationOptions; if (typeof mapPropsToOptions !== 'function') - mapPropsToOptions = () => options as BaseMutationOptions; + mapPropsToOptions = () => options as BaseMutationOptions; return ( WrappedComponent: React.ComponentType @@ -54,7 +56,7 @@ export function withMutation< static WrappedComponent = WrappedComponent; render() { let props = this.props as TProps; - const opts = mapPropsToOptions(props); + const opts = mapPropsToOptions(props) as BaseMutationOptions; if (operationOptions.withRef) { this.withRef = true; @@ -63,7 +65,7 @@ export function withMutation< }); } if (!opts.variables && operation.variables.length > 0) { - opts.variables = calculateVariablesFromProps(operation, props); + opts.variables = calculateVariablesFromProps(operation, props) as TGraphQLVariables; } return ( diff --git a/src/react/hoc/types.ts b/src/react/hoc/types.ts index dddfe8d6f1f..6298928d816 100644 --- a/src/react/hoc/types.ts +++ b/src/react/hoc/types.ts @@ -7,6 +7,7 @@ import { UpdateQueryOptions, FetchMoreQueryOptions, SubscribeToMoreOptions, + Context, } from '../../core'; import { MutationFunction, @@ -89,16 +90,17 @@ export interface OperationOption< TProps, TData, TGraphQLVariables = OperationVariables, - TChildProps = ChildProps + TChildProps = ChildProps, + TContext = Context, > { options?: | BaseQueryOptions - | BaseMutationOptions + | BaseMutationOptions | (( props: TProps ) => | BaseQueryOptions - | BaseMutationOptions + | BaseMutationOptions ); props?: ( props: OptionProps, diff --git a/src/react/hooks/__tests__/useMutation.test.tsx b/src/react/hooks/__tests__/useMutation.test.tsx index ed0d4893baa..8e703a39ad9 100644 --- a/src/react/hooks/__tests__/useMutation.test.tsx +++ b/src/react/hooks/__tests__/useMutation.test.tsx @@ -428,6 +428,134 @@ describe('useMutation Hook', () => { }); }); + describe('Update function', () => { + + itAsync('should be called with the provided variables', async (resolve, reject) => { + const variables = { + description: 'Get milk!' + }; + + const mocks = [ + { + request: { + query: CREATE_TODO_MUTATION, + variables + }, + result: { data: CREATE_TODO_RESULT } + } + ]; + + const Component = () => { + const [createTodo] = useMutation( + CREATE_TODO_MUTATION, + { + update(_, __, options) { + expect(options.variables).toEqual(variables); + resolve(); + } + } + ); + + useEffect(() => { + createTodo({ variables }); + }, []); + + return null; + }; + + render( + + + + ); + }); + + itAsync('should be called with the provided context', async (resolve, reject) => { + const context = { id: 3 }; + + const variables = { + description: 'Get milk!' + }; + + const mocks = [ + { + request: { + query: CREATE_TODO_MUTATION, + variables + }, + result: { data: CREATE_TODO_RESULT } + } + ]; + + const Component = () => { + const [createTodo] = useMutation( + CREATE_TODO_MUTATION, + { + context, + update(_, __, options) { + expect(options.context).toEqual(context); + resolve(); + } + } + ); + + useEffect(() => { + createTodo({ variables }); + }, []); + + return null; + }; + + render( + + + + ); + }); + + describe('If context is not provided', () => { + itAsync('should be undefined', async (resolve, reject) => { + const variables = { + description: 'Get milk!' + }; + + const mocks = [ + { + request: { + query: CREATE_TODO_MUTATION, + variables + }, + result: { data: CREATE_TODO_RESULT } + } + ]; + + const Component = () => { + const [createTodo] = useMutation( + CREATE_TODO_MUTATION, + { + update(_, __, options) { + expect(options.context).toBeUndefined(); + resolve(); + } + } + ); + + useEffect(() => { + createTodo({ variables }); + }, []); + + return null; + }; + + render( + + + + ); + }); + }); + }); + describe('Optimistic response', () => { itAsync('should support optimistic response handling', async (resolve, reject) => { const optimisticResponse = { @@ -504,6 +632,66 @@ describe('useMutation Hook', () => { expect(renderCount).toBe(3); }).then(resolve, reject); }); + + itAsync('should be called with the provided context', async (resolve, reject) => { + const optimisticResponse = { + __typename: 'Mutation', + createTodo: { + id: 1, + description: 'TEMPORARY', + priority: 'High', + __typename: 'Todo' + } + }; + + const context = { id: 3 }; + + const variables = { + description: 'Get milk!' + }; + + const mocks = [ + { + request: { + query: CREATE_TODO_MUTATION, + variables + }, + result: { data: CREATE_TODO_RESULT } + } + ]; + + const contextFn = jest.fn(); + + const Component = () => { + const [createTodo] = useMutation( + CREATE_TODO_MUTATION, + { + optimisticResponse, + context, + update(_, __, options) { + contextFn(options.context); + } + } + ); + + useEffect(() => { + createTodo({ variables }); + }, []); + + return null; + }; + + render( + + + + ); + + return wait(() => { + expect(contextFn).toHaveBeenCalledTimes(2); + expect(contextFn).toHaveBeenCalledWith(context); + }).then(resolve, reject); + }); }); describe('refetching queries', () => { diff --git a/src/react/hooks/useMutation.ts b/src/react/hooks/useMutation.ts index 28f96618c0f..38b3579d629 100644 --- a/src/react/hooks/useMutation.ts +++ b/src/react/hooks/useMutation.ts @@ -4,21 +4,25 @@ import { TypedDocumentNode } from '@graphql-typed-document-node/core'; import { MutationHookOptions, MutationTuple } from '../types/types'; import { MutationData } from '../data'; -import { OperationVariables } from '../../core'; +import { Context, OperationVariables } from '../../core'; import { getApolloContext } from '../context'; -export function useMutation( +export function useMutation< + TData = any, + TVariables extends OperationVariables = OperationVariables, + TContext extends Context = Context +>( mutation: DocumentNode | TypedDocumentNode, - options?: MutationHookOptions -): MutationTuple { + options?: MutationHookOptions +): MutationTuple { const context = useContext(getApolloContext()); const [result, setResult] = useState({ called: false, loading: false }); const updatedOptions = options ? { ...options, mutation } : { mutation }; - const mutationDataRef = useRef>(); + const mutationDataRef = useRef>(); function getMutationDataRef() { if (!mutationDataRef.current) { - mutationDataRef.current = new MutationData({ + mutationDataRef.current = new MutationData({ options: updatedOptions, context, result, diff --git a/src/react/types/types.ts b/src/react/types/types.ts index c91f837f342..f775a2a0734 100644 --- a/src/react/types/types.ts +++ b/src/react/types/types.ts @@ -8,11 +8,12 @@ import { ApolloError } from '../../errors'; import { ApolloClient, ApolloQueryResult, + Context, ErrorPolicy, FetchMoreOptions, FetchMoreQueryOptions, FetchPolicy, - MutationUpdaterFn, + MutationUpdaterFunction, NetworkStatus, ObservableQuery, OperationVariables, @@ -24,8 +25,6 @@ import { /* Common types */ -export type Context = Record; - export type CommonOptions = TOptions & { client?: ApolloClient; }; @@ -141,19 +140,20 @@ export type RefetchQueriesFunction = ( ) => Array; export interface BaseMutationOptions< - TData = any, - TVariables = OperationVariables + TData, + TVariables extends OperationVariables, + TContext extends Context, > { variables?: TVariables; optimisticResponse?: TData | ((vars: TVariables) => TData); refetchQueries?: Array | RefetchQueriesFunction; awaitRefetchQueries?: boolean; errorPolicy?: ErrorPolicy; - update?: MutationUpdaterFn; + update?: MutationUpdaterFunction; reobserveQuery?: ReobserveQueryCallback; client?: ApolloClient; notifyOnNetworkStatusChange?: boolean; - context?: Context; + context?: TContext; onCompleted?: (data: TData) => void; onError?: (error: ApolloError) => void; fetchPolicy?: Extract; @@ -161,16 +161,17 @@ export interface BaseMutationOptions< } export interface MutationFunctionOptions< - TData = any, - TVariables = OperationVariables + TData, + TVariables, + TContext, > { variables?: TVariables; optimisticResponse?: TData | ((vars: TVariables) => TData); refetchQueries?: Array | RefetchQueriesFunction; awaitRefetchQueries?: boolean; - update?: MutationUpdaterFn; + update?: MutationUpdaterFunction; reobserveQuery?: ReobserveQueryCallback; - context?: Context; + context?: TContext; fetchPolicy?: WatchQueryFetchPolicy; } @@ -183,27 +184,33 @@ export interface MutationResult { } export declare type MutationFunction< - TData = any, - TVariables = OperationVariables + TData, + TVariables = OperationVariables, + TContext = Context, > = ( - options?: MutationFunctionOptions + options?: MutationFunctionOptions ) => Promise>; export interface MutationHookOptions< TData = any, - TVariables = OperationVariables -> extends BaseMutationOptions { + TVariables = OperationVariables, + TContext = Context, +> extends BaseMutationOptions { mutation?: DocumentNode | TypedDocumentNode; } -export interface MutationDataOptions - extends BaseMutationOptions { +export interface MutationDataOptions< + TData, + TVariables extends OperationVariables, + TContext extends Context +> + extends BaseMutationOptions { mutation: DocumentNode | TypedDocumentNode; } -export type MutationTuple = [ +export type MutationTuple = [ ( - options?: MutationFunctionOptions + options?: MutationFunctionOptions ) => Promise>, MutationResult ];