What's the proper way to write subscribeToMore.updateQuery in Typescript?

I’m running into some TypeScript challenges after upgrading to Apollo Client 4.x.

I’m following this example provided in the docs for using subscribeToMore() from useQuery()

The code example has this:

const unsubscribe = subscribeToMore({
        document: COMMENTS_SUBSCRIPTION,
        variables: { postID: params.postID },
        updateQuery: (prev, { subscriptionData }) => {
          if (!subscriptionData.data) return prev;
          const newFeedItem = subscriptionData.data.commentAdded;
          return Object.assign({}, prev, {
            post: {
              comments: [newFeedItem, ...prev.post.comments],
            },
          });
        },
      });

However, in my TypeScript project this causes a typescript error because it complains that prev could be DeepPartialObject, and you are not allowed to return a DeepPartialObject from the updateQuery function. The only workaround I could find was just to cast the output to not be DeepPartialObject, but that seems wrong.

What is the proper way to convert DeepPartialObjects into something that updateQuery can return?

Thanks for your help!

Yeah, we noticed that too, but most changes would have been extremely breaking.

So we introducted additional properties complete, previousData on the options object passed into updateQuery.

You’d use those like this:

const unsubscribe = subscribeToMore({
        document: COMMENTS_SUBSCRIPTION,
        variables: { postID: params.postID },
        updateQuery: (_, { subscriptionData, complete, previousData }) => {
          if (!subscriptionData.data || !complete) return previousData;
          const newFeedItem = subscriptionData.data.commentAdded;
          return Object.assign({}, previousData, {
            post: {
              comments: [newFeedItem, ...previousData.post.comments],
            },
          });
        },
      });

hmm, in my testing this will cause a typescript error because previousData is typed as a DeepPartialObject when complete !== true, and the definition for updateQuery() does not allow that. You could just return undefined, and that would make TypeScript happy I think, but would cause us to ignore the incoming subscriptionData and it would never get added to the list of comments in this example. I’m pretty sure this is the behavior I’ve observed in my application, which does something pretty similar to this example.

Ah, my fault, I’m sorry - you wouldn’t return previousData in the incomplete case, just return undefined - that means the result should stay unchanged.

And my fault again, I’m sorry, I didn’t read this closely enough.

Generally, I think undefined is still the best call, because when your cache data is not complete, there is probably no safe way to merge the new result into the old one and you’ll have to make a choice between only old (undefined) or only new data.

That said, in reality this should only ever happen in edge case scenarios, e.g. when you call subscribeToMore and get results back before the query itself finished.

But you should probably log this and treat it as a potential bug in your application in that case.