Repository: apollographql/apollo-client

Problem statement:
UseFragment producing a warning during store misses (TypeError: Cannot read properties of undefined)
### Issue Description

Since @apollo/client 3.11.5 I've started receiving warnings in the console during store misses of useFragment in development: `TypeError: Cannot read properties of undefined (reading '__typename')`

A bit of testing suggests that this happens in all my uses of useFragment during store misses.
Note that although I get the warning, everything continues to work fine. @apollo/client 3.11.4 did not have this issue.

In case it's relevant I'm using the following arguments on useFragment: `fragment, fragmentName, from: {__typename: X, id: X}`



The full stack trace is:
```
TypeError: Cannot read properties of undefined (reading '__typename')
    at Policies2.identify (policies.ts:360:14)
    at InMemoryCache2.identify (inMemoryCache.ts:350:28)
    at ApolloCache2.watchFragment (cache.ts:232:50)
    at useFragment.ts:105:36
    at subscribeToStore (react-dom.development.js:16139:10)
    at commitHookEffectListMount (react-dom.development.js:23189:26)
    at invokePassiveEffectMountInDEV (react-dom.development.js:25193:13)
    at invokeEffectsInDev (react-dom.development.js:27390:11)
    at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27369:7)
    at flushPassiveEffectsImpl (react-dom.development.js:27095:5)
```

### Link to Reproduction

None

### Reproduction Steps

Call useFragment on any fragment which hasn't been loaded into the FE cache/store by typename + id.

### `@apollo/client` version

3.11.5


Hints:
Hey @alex-e-leon!

You beat me to opening this 😆. I discovered this just recently working with the data masking feature. We did some rework with `useFragment` to ensure it follows the Rules of React (specifically not writing to `ref` in render), but I just found out that causes this warning. I know exactly where the issue is coming from so I'll get a PR out for this very soon (hopefully today). So sorry about the additional noise!
This is the punishment I get for staying up to date with all the latest deps : )

And thanks @jerelmiller - its great to get such fast feedback and see that you're already on top of it!

Patch:
diff --git a/src/cache/core/cache.ts b/src/cache/core/cache.ts
--- a/src/cache/core/cache.ts
+++ b/src/cache/core/cache.ts
@@ -229,7 +229,16 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
     const diffOptions: Cache.DiffOptions<TData, TVars> = {
       ...otherOptions,
       returnPartialData: true,
-      id: typeof from === "string" ? from : this.identify(from),
+      id:
+        // While our TypeScript types do not allow for `undefined` as a valid
+        // `from`, its possible `useFragment` gives us an `undefined` since it
+        // calls` cache.identify` and provides that value to `from`. We are
+        // adding this fix here however to ensure those using plain JavaScript
+        // and using `cache.identify` themselves will avoid seeing the obscure
+        // warning.
+        typeof from === "undefined" || typeof from === "string" ?
+          from
+        : this.identify(from),
       query,
       optimistic,
     };


Test patch:
diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx
--- a/src/react/hooks/__tests__/useFragment.test.tsx
+++ b/src/react/hooks/__tests__/useFragment.test.tsx
@@ -1725,6 +1725,34 @@ describe("useFragment", () => {
       });
     });
   });
+
+  // https://github.com/apollographql/apollo-client/issues/12051
+  it("does not warn when the cache identifier is invalid", async () => {
+    using _ = spyOnConsole("warn");
+    const cache = new InMemoryCache();
+
+    const ProfiledHook = profileHook(() =>
+      useFragment({
+        fragment: ItemFragment,
+        // Force a value that results in cache.identify === undefined
+        from: { __typename: "Item" },
+      })
+    );
+
+    render(<ProfiledHook />, {
+      wrapper: ({ children }) => (
+        <MockedProvider cache={cache}>{children}</MockedProvider>
+      ),
+    });
+
+    expect(console.warn).not.toHaveBeenCalled();
+
+    const { data, complete } = await ProfiledHook.takeSnapshot();
+
+    // TODO: Update when https://github.com/apollographql/apollo-client/issues/12003 is fixed
+    expect(complete).toBe(true);
+    expect(data).toEqual({});
+  });
 });
 
 describe("has the same timing as `useQuery`", () => {