Skip to content
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

TypeScript Resolvers: Easier way to get possible resolve types for interfaces #6443

Open
Tracked by #8296 ...
tobiasdiez opened this issue Aug 8, 2021 · 3 comments
Open
Tracked by #8296 ...
Labels
core Related to codegen core/cli help wanted Extra attention is needed kind/enhancement New feature or request

Comments

@tobiasdiez
Copy link
Contributor

Is your feature request related to a problem? Please describe.

If you have an interface Document and multiple types implementing it, say Article, Thesis and Other, then the typescript resolvers generated looks similar to

export type DocumentResolvers<ContextType = Context, ParentType extends ResolversParentTypes['Document'] = ResolversParentTypes['Document']> = ResolversObject<{
  __resolveType: TypeResolveFn<'Article' | 'Thesis' | 'Other', ParentType, ContextType>;
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
  ....
}>;

As one can see, the implementing types are listed explicitly in the definition of the __resolveType function. Thus, they cannot easily be reused, which is mildly annoying if you want/need to use another function to return exactly one of the options (say because you need to parse or check other data to determine which of the types should be returned). A function like this would currently be annotated like

parse(input: any): 'Article' | 'Thesis' | 'Other'

This is prone to break in the future if other types implementing the interface are added, and leads to code duplication.

Describe the solution you'd like

Extract the possible type names to a separate type. Maybe even auto-generating something like

const DocumentResolveTypes = ['Article' | 'Thesis' | 'Other'] as const;
type DocumentResolveTypes = typeof DocumentResolveTypes [number];

so that one can easily iterate over the possible types.

Describe alternatives you've considered
I'm currently using the following code as a work-around.

type ResolveFnc<TResolver extends ResolversObject<unknown>> =
  TResolver extends {
    __resolveType: infer T
  }
    ? T
    : never

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : unknown
/**
 * Type to extract the resolve type from a resolver for unions / interfaces.
 */
type ResolveType<TResolver extends ResolversObject<unknown>> = ReturnType<
  ResolveFnc<TResolver>
>

ResolveType<DocumentResolvers> // 'Article' | 'Thesis' | 'Other'
@dotansimha dotansimha added help wanted Extra attention is needed kind/enhancement New feature or request labels Sep 6, 2021
@dotansimha
Copy link
Owner

Hi @tobiasdiez !
This sounds like a nice idea, and a possible implementation alternative. If you want, feel free to create a PR for adding that!

@alexstrat
Copy link

alexstrat commented Dec 9, 2021

I came across graphql-typescript-possible-types that could be used for this use-case as well:

import { possibleTypes } from './generated'
type DocumentPossibleTypeName = typeof possibleTypes['Document'][number] // 'Article' | 'Thesis' | 'Other'

@ksrb
Copy link

ksrb commented Apr 27, 2022

Example of using graphql-typescript-possible-types mentioned by alexstrat.

npm i @homebound/graphql-typescript-possible-types

codegen.yml

generates:
  integration/graphql-types.ts:
    plugins:
      - node_modules/@homebound/graphql-typescript-possible-types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Related to codegen core/cli help wanted Extra attention is needed kind/enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants