Reputation: 1723
I get a nested object as result of a GraphQL query with the query name as first-level key and the actual data on the second level:
{
getProduct: {
id: "1",
name: "test",
}
}
In my query function I automatically extract the first key of the object and return the value of getProduct
. However, I would like to infer the type of the first key as the return value of the query function.
type QueryReturn = FirstElement<GetProductQuery>; // should be { id: string; name: string }
All solutions I've found on the Internet infer the Head or Tail of an Array or Function.
Upvotes: 3
Views: 2433
Reputation: 594
depending on your requirements, one can also choose to alias his queries to normalize their result.
Take following code :
export const MyComponent_FooEntity_QueryDocument = graphql(`
query MyComponent_FooEntity_Query($id: Id!) {
findMyFoo(id: $id) {
# Fields
}
}
`)
export const MyComponent_BarEntity_QueryDocument = graphql(`
query MyComponent_BarEntity_Query($id: Id!) {
findMyBar(id: $id) {
# Fields
}
}
`)
You can change it to :
export const MyComponent_FooEntity_QueryDocument = graphql(`
query MyComponent_FooEntity_Query($id: Id!) {
queryResult: findMyFoo(id: $id) {
# Fields
}
}
`)
export const MyComponent_BarEntity_QueryDocument = graphql(`
query MyComponent_BarEntity_Query($id: Id!) {
queryResult: findMyBar(id: $id) {
# Fields
}
}
`)
Like so, you can access your data type in a normalized way :
import type { ResultOf } from '@graphql-typed-document-node/core';
type QueryResult = ResultOf<
typeof MyComponent_BarEntity_QueryDocument
>['queryResult']
or a utility function :
export const getQueryResult = <R,>(query: { readonly queryResult: R }): R => query.queryResult
Upvotes: 0
Reputation: 366
Bit late. if you can assure that you always have single key in the outmost type, you can do it by utilizing keyof
operator and indexed access type.
This will behave strangely if you have no keys or more than one key in the outmost type, so make sure you always have the exact one key in all scenario.
Example:
type Unwrap<T> = T[keyof T];
type QueryReturn = Unwrap<GetProductQuery>;
Upvotes: 2
Reputation: 60
I'm a bit late to the party but I saw that you were using graphql-codegen. I had a similar problem which I solved with:
type DataType = {
__typename?: string;
};
type FilteredQuery<T> = {
[P in keyof T as T[P] extends DataType ? P : never]: T[P];
};
type QueryData<T> = FilteredQuery<T>[keyof FilteredQuery<T>];
TypeScript playground example.
Upvotes: 4
Reputation: 787
Am I understanding correctly that you just want to get to the product type without the getProduct
alias in the middle?
I get the hunch this extra level is there because you are aliasing your query. Regardless, there is no first key in an object. The way to drill down would be to specify the key. This can all be made much easier by auto-generating types with a tool like graphql-autogen.
Upvotes: 0