diff --git a/.changeset/brave-buttons-grab.md b/.changeset/brave-buttons-grab.md
new file mode 100644
index 00000000000..18c136161ed
--- /dev/null
+++ b/.changeset/brave-buttons-grab.md
@@ -0,0 +1,5 @@
+---
+"@apollo/client": patch
+---
+
+Deprecate `useFragment` `returnPartialData` option
diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx
index dab0f5efcb5..5e7f8ed5adf 100644
--- a/src/react/hooks/__tests__/useFragment.test.tsx
+++ b/src/react/hooks/__tests__/useFragment.test.tsx
@@ -911,4 +911,94 @@ describe("useFragment", () => {
]);
});
});
+
+ describe("tests with incomplete data", () => {
+ let cache: InMemoryCache, wrapper: React.FunctionComponent;
+ const ItemFragment = gql`
+ fragment ItemFragment on Item {
+ id
+ text
+ }
+ `;
+
+ beforeEach(() => {
+ cache = new InMemoryCache();
+
+ wrapper = ({ children }: any) => {children};
+
+ // silence the console for the incomplete fragment write
+ const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ cache.writeFragment({
+ fragment: ItemFragment,
+ data: {
+ __typename: "Item",
+ id: 5,
+ },
+ });
+ spy.mockRestore();
+ });
+
+ it("assumes `returnPartialData: true` per default", () => {
+ const { result } = renderHook(
+ () =>
+ useFragment({
+ fragment: ItemFragment,
+ from: { __typename: "Item", id: 5 },
+ }),
+ { wrapper }
+ );
+
+ expect(result.current.data).toEqual({ __typename: "Item", id: 5 });
+ expect(result.current.complete).toBe(false);
+ });
+
+ it("throws an exception with `returnPartialData: false` if only partial data is available", () => {
+ // this is actually not intended behavior, but it is the current behavior
+ // let's document it in a test until we remove `returnPartialData` in 3.8
+
+ let error: Error;
+
+ renderHook(
+ () => {
+ // we can't just `expect(() => renderHook(...)).toThrow(...)` because it will render a second time, resulting in an uncaught exception
+ try {
+ useFragment({
+ fragment: ItemFragment,
+ from: { __typename: "Item", id: 5 },
+ returnPartialData: false,
+ });
+ } catch (e) {
+ error = e;
+ }
+ },
+ { wrapper }
+ );
+
+ expect(error!.toString()).toMatch(`Error: Can't find field 'text' on Item:5 object`);
+ });
+
+ it("throws an exception with `returnPartialData: false` if no data is available", () => {
+ // this is actually not intended behavior, but it is the current behavior
+ // let's document it in a test until we remove `returnPartialData` in 3.8
+ let error: Error;
+
+ renderHook(
+ () => {
+ // we can't just `expect(() => renderHook(...)).toThrow(...)` because it will render a second time, resulting in an uncaught exception
+ try {
+ useFragment({
+ fragment: ItemFragment,
+ from: { __typename: "Item", id: 6 },
+ returnPartialData: false,
+ });
+ } catch (e) {
+ error = e;
+ }
+ },
+ { wrapper }
+ );
+
+ expect(error!.toString()).toMatch(`Error: Dangling reference to missing Item:6 object`);
+ });
+ });
});
diff --git a/src/react/hooks/useFragment.ts b/src/react/hooks/useFragment.ts
index 187a83222aa..5bf0a282958 100644
--- a/src/react/hooks/useFragment.ts
+++ b/src/react/hooks/useFragment.ts
@@ -20,13 +20,22 @@ extends Omit<
| "query"
| "optimistic"
| "previousResult"
->, Omit<
- Cache.ReadFragmentOptions,
+ | "returnPartialData"
+>, Omit,
| "id"
+ | "returnPartialData"
> {
from: StoreObject | Reference | string;
// Override this field to make it optional (default: true).
optimistic?: boolean;
+
+ /**
+ * Whether to return incomplete data rather than null.
+ * Defaults to `true`.
+ * @deprecated This option will be removed in Apollo Client 3.8.
+ * Please check `result.missing` instead.
+ */
+ returnPartialData?: boolean;
}
// Since the above definition of UseFragmentOptions can be hard to parse without