We are trying to upgrade from @apollo/client v3.10 to v3.12 and are running into TypeScript errors with the new data masking. We have a standard and all our mutations return a structure like:
export type MutationResponse<P extends string> = {
[K in P]: {
message: string;
status: "SUCCESS" | "FAILURE";
};
};
(That was not my design, but that’s what we have and I need to work with that.)
In order to abstract our code from the details of the response, we have a wrapper hook that looks like (simplified):
export function useBgxMutation<Key extends string>(
mutation: Parameters<typeof useMutation>[0],
key: Key,
options?: MutationOptions<MutationResponse<Key>>,
) {
const [execute, { loading, error, data}] = useMutation<MutationResponse<Key>>(mutation, options);
const foo = data?.[key]; // <-- now fails with Type 'Key' cannot be used to index type 'NonNullable<MaybeMasked<MutationResponse<Key>>>'.
// other boiler plate code to deal with errors, loading state, etc.
const wrapper = async (/* various params for internal use */) => {
const res = await execute(execOptions);
if(res?.data?.[key].status !== "SUCCESS") { // <-- here, also getting error: Type 'Key' cannot be used to index type 'NonNullable<MaybeMasked<MutationResponse<Key>>>'
// Deal with error
}
// Deal with success...
}
return [execute, {...}];
}
We do not intend on using Data Masking (probably because we cannot figure out what problem it is trying to solve - we never had any issues in 5 years with 100+ queries and mutations…). So, how do we properly unwrap that response to be able to access the data the way we have for the past 5 years? Yes, we can just cast whatever we want to whatever else we want. But we were hoping there was a clean way of doing that since Data Masking has been advertised as optional for this minor release.
ironically, most of the TS work we have to do is to make sure that you get working types when data masking is turned off, but are accidentally using the GraphQL Codegen “client preset”, which generates kinda masked types anyways - so if you turn it on on a type level, but keep it off at runtime, everything will keep working for you as it did before.
To do that, create a apollo-client.d.ts in your repo:
// This import is necessary to ensure all Apollo Client imports
// are still available to the rest of the application.
import '@apollo/client';
declare module "@apollo/client" {
interface DataMasking {
enabled: true;
}
}
After that, everything should be as before.
probably because we cannot figure out what problem it is trying to solve
Gonna try a short sales pitch here
You should see a massive performance boost as rerenders will apply much more granularly only if the part of a query is actually used by a component, as opposed to “anything kinda related can cause a rerender”.
It also allows for “route-level” queries, removing all network waterfalls for your app, while helping you organize your application in a way where you can define data dependencies of a component where you need the data, not potentially files away from it.
I’ve been running into the same error mentioned by @ericl when updating from v3.10 to v3.12. I’ve attempted the recommended fix, adding the apollo-client.d.ts file to my project. However, I’m still running into the same error:
'Key' cannot be used to index type 'NonNullable<MaybeMasked<MutationResponse<Key>>>'
Do you happen to have any suggestions on other potential fixes?
Hmm, I would assume that for some reason the .d.ts might not be picked up in your case.
That said, we will be pushing a change soon that will change the default to be easier to integrate with, so please wait for the next patch release on that.