-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Typescript helper for drilling into nested types? #2832
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
Comments
A "workaround" would be using Fragments for defining the Data a single component should receive. You can then use the generated Fragment type as a prop/props. I would categorize this as the relay way. |
👍 Thanks @n1ru4l. Fragments definitely have a place, but I think defining them for every query can add unnecessary noise/overhead. A general purpose type that can focus on a specific part of the response keeps the query semantics cleaner for ad hoc queries, IMO. I wound using ts-toolbelt to provide a 'lens' into a query. A modified version will soon be available in the lib as I'll close this for now, since this addresses my specific use-case |
Thanks @leebenson ! |
Excellent! As a starting point, millsp/ts-toolbelt#64 (comment) is what I wound up going with (with some minor changes.) I also created a // Discriminate on __typename
type Typename<T, K> = T extends { __typename?: K }
? import("ts-toolbelt").Union.Select<
import("ts-toolbelt").Object.Required<NonNullable<T>, "__typename">,
{ __typename: K }
>
: never; That could probably be cleaned up a little, but it works well for my use-case. |
Nice! Actually we have some code that does discrimination for TS types under |
I am really quite disappointed with the 1.0 release of this project. It removed a lot of what made this tool better than the rest. You could separate client and server types, have namespaces that made the Query response types easy to get at. typescript-compatibility helps, sure, but it sounds temporary and not a long term solution. typescript-compatibility is also riddled with bugs around fragments. We previously used the types within the namespace to pass around as props, making all these a fragment is not really a great solution as we don't intend for these fragments to be re-used. It also adds request overhead (sure, its minimal), and the fragments to be defined away out of the context of the property they are spread in. |
Sure you should seperate client-side and server-side code generation and we already have separated packages for those two purposes. |
With the new typings being generated and recommendations of using fragments, and when the majority of your responses are passed around as props, then it requires you to turn everything into a fragment. The other issue with fragments is it can re-introduce overfetching, as any time you need access to a new property, you add it to the fragment, where as not all areas using the fragment need access to this. In cases where you aren't leveraging apollo cache, this causes overfetching. Sure, you could add the one field to the query along with the fragment, but now you are back to issues with not being able to use the fragment for a complete typing to pass around. Also, I cannot find anything regarding namespaces being deprecated in TypeScript. According to the following, it is not deprecated.
Regarding Babel, they re-introduced namespace support. |
Have you found a general solution for when a response has nested properties that are unions you'd like to narrow from the top level? i.e. You get a query response where the root entity can be of several Would love to hear how far you got with this approach. Discriminating at a single level is straightforward, but it'd be excellent to narrow an entire object down rather than needing to check at each union as you access it in your application code, if that makes sense. |
what do you use in 2023? 👀 |
Still no particularly good solutions in 2023. |
This is part question, part feature request.
I'm curious if anyone has uncovered a useful pattern or helper library for drilling into deeply nested, complex GraphQL response types, especially those that have unions along the path?
I'm curious @dotansimha if you've thought about adding some helper types to the lib to help drill down to specific parts of the graph?
Motivation
I have a lot of queries like this:
This looks pretty simple, but there are some tricky paths:
node
is an interface of many possible typessavedQueries
andedges
are arraysviews
is an array of interface typesThe generated response type looks like this (I've omitted some of the graph for brevity):
What I'd like to be able to do is dynamically type any arbitrary section of
SomeQuery
.Use case
The primary use case is to type React child components that accept data from a parent, which is typically a subset of the full response.
Current approach
For now, we're writing quite convoluted types that wind up looking like this (not related to the above query, but the general approach):
This is fine for basic queries, but for any where unions/interfaces form part of the response, there's additional inference and unpacking to go down certain paths.
I've looked at ts-toolbelt as an option to drill into types, which looks promising, but haven't figured out a general approach yet.
Ideal helper
Possibly with the help of recursive types in TS 3.7, I'm wondering if there's a way we might end up with a generic
Query
helper which can be used to probe arbitrary levels.Something like the following would be awesome:
Any child React component could then just have
node: Node
as a prop, and the shape would match a specific query exactly, instead of having to either a) take a full SomeQuery or b) use the 'raw' type of the inner key, which is then unsafe because the field selection doesn't match this specific query.Are there any plans to add helpers to the lib? Or perhaps any useful third-party libs that can get us close to the
Query
helper?Would really appreciate any recommendations and love to hear how others are solving this.
Thanks!
The text was updated successfully, but these errors were encountered: