-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update Context Types #12104
Update Context Types #12104
Conversation
👷 Deploy request for apollo-client-docs pending review.Visit the deploys page to approve it
|
✅ Docs Preview ReadyNo new or changed pages found. |
|
src/core/ApolloClient.ts
Outdated
@@ -474,7 +475,7 @@ export class ApolloClient<TCacheShape> implements DataProxy { | |||
public mutate< | |||
TData = any, | |||
TVariables extends OperationVariables = OperationVariables, | |||
TContext extends Record<string, any> = DefaultContext, | |||
TContext extends OperationContext = Partial<DefaultContext>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a new type called OperationContext
to represent Record<string, any>. I wanted to call it Context
but
apollo-client/src/react/types/types.ts
Line 43 in 6496b25
export type { DefaultContext as Context } from "../../core/index.js"; |
src/link/context/index.ts
Outdated
export function setContext< | ||
TContext extends OperationContext = Partial<DefaultContext>, | ||
>(setter: ContextSetter<TContext>): ApolloLink { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the types here to reflect that users only need to pass in a partial of the context.
apollo-client/src/link/utils/createOperation.ts
Lines 8 to 15 in 4ebebf0
const setContext: Operation["setContext"] = (next) => { | |
if (typeof next === "function") { | |
context = { ...context, ...next(context) }; | |
} else { | |
context = { ...context, ...next }; | |
} | |
}; | |
const getContext: Operation["getContext"] = () => ({ ...context }); |
But I also thought that users might want to strictly type what they want to return here so I've given the flexibility to pass in TContext.
src/core/QueryManager.ts
Outdated
query, | ||
fetchPolicy, | ||
errorPolicy = "none", | ||
variables, | ||
context = {}, | ||
context = {} as TContext, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not particularly sure what the defaulting is for here but I decided to leave it in to avoid any breaking change and am choosing to cast here instead.
Not sure why the tests are failing as there are no code changes in this PR |
Should this be required? If we're typing DefaultContext, I would expect this to be filled on client creation? apollo-client/src/core/ApolloClient.ts Line 119 in 6496b25
If they need it to be optional they could declare it themselves while extending it |
Hi Sam, |
No problems, we're all busy people! Fully understand, thanks for the reply |
src/core/ApolloClient.ts
Outdated
@@ -116,7 +117,7 @@ export interface ApolloClientOptions<TCacheShape> { | |||
* See this [example object](https://www.apollographql.com/docs/react/api/core/ApolloClient#example-defaultoptions-object). | |||
*/ | |||
defaultOptions?: DefaultOptions; | |||
defaultContext?: Partial<DefaultContext>; | |||
defaultContext?: DefaultContext; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes sense, if you are expecting something to always be in here, you would declare it as Required on the default context?
Unless we're intentionally making this Partial so you could type things like headers: Record<string, string>
as Apollo seems to always inject these
Sorry for the late response, this is one of those where I'm going forth and back on it and I need to reserve a lot of headspace for reviewing to do it justice. Some thoughts (without a final call!) here:
Maybe adding a bit of history on the intent behind adding All that said, and especially regarding the first point " |
da10778
to
e91aeaf
Compare
Hmmm I was kinda hoping for the following flow: client const client = new ApolloClient({
defaultContext: {
getToken: () => {}
}
}); Then within my ApolloLinks I could access it without needing to cast or check for the field all the time. But if you feel we shouldn't type it like that I understand. const authLink = setContext(async (_, context) => {
const {
headers,
getToken,
} = context;
const token = await getToken();
return {
...context,
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
};
}); |
The problem is that even if you do new ApolloClient({
cache,
link
})
// or
new ApolloClient({
cache,
link,
defaultContext
}) So you have no way of knowing if This also makes sense, as historically, there was no => My recommendation would be right now to treat everything in |
That's fair enough okie thanks for the explanation |
Checklist:
The tl;dr
context
type on all operations must now extendOperationContext
(Record<string, any>
) and defaults toPartial<DefaultContext>
context
field now requires a non partialDefaultContext
.In Depth
I was trying to work with @phryneas comment here: apollographql/apollo-client-nextjs#103 (comment)
by setting a
defaultContext
type:eg.
However, this had cascading effects to the other operations such as useQuery where suddenly the operation inputs were expecting
appContext
to be in the context which is incorrect as we should only require a partial of the default context to allow for overwritingSo I decided to go and fix the query type but realised the mutation type allows the Context to be set:
apollo-client/src/core/watchQueryOptions.ts
Line 252 in 6496b25
So in the name of consistency I went to try and add generics for the Query types and many changes later here we are.