Replies: 1 comment
-
Here's a workaround I came up with: import { GraphQLScalarType } from 'graphql';
import { Resolver as GQLResolver, ResolverTypeWrapper as GQLResolverTypeWrapper } from './generated-types';
/**
* Outputs Base combined with Overrides, where Overrides take precedence in the case of conflicts
*/
type Override<Base, Overrides> = Omit<Base, keyof Overrides> & Overrides;
type AlwaysOptionalResolvers = '__resolveReference' | '__isTypeOf';
/**
* The names of all the actual fields on a given object type, not including special resolvers like __resolveReference
*/
type FieldResolverNames<ObjectResolvers> = Exclude<keyof ObjectResolvers, AlwaysOptionalResolvers>;
/**
* Extends a nullable type to also allow undefined; otherwise, returns the type itself.
*/
type IfNullableAlsoOptional<T> = null extends T ? T | undefined : T;
/**
* The type that must be returned for a field resolver
*/
type ResolverResult<Resolver> = Resolver extends GQLResolver<GQLResolverTypeWrapper<infer Result>, any, any, any>
? Result
: never;
/**
* Gets the parent type for a given resolver
*/
type ParentType<Resolver> = Resolver extends GQLResolver<any, infer Parent, any, any> ? Parent : never;
/**
* Resolves to unknown if a key doesn't exist on a given type
*/
type OptionalFieldOnObject<Object, FieldName> = FieldName extends keyof Object ? Object[FieldName] : unknown;
/**
* The type that will be resolved for a given field if no explicit resolver is provided.
*/
type BackingFieldType<ObjectResolvers, FieldName extends keyof ObjectResolvers> = OptionalFieldOnObject<
ParentType<NonNullable<ObjectResolvers[FieldName]>>,
FieldName
>;
/**
* All resolvers for fields on this particular object that can't be resolved directly from the backing type
*/
type ObjectResolversRequiredFields<ObjectResolvers> = {
[K in FieldResolverNames<ObjectResolvers> as BackingFieldType<ObjectResolvers, K> extends IfNullableAlsoOptional<
ResolverResult<NonNullable<ObjectResolvers[K]>>
>
? never
: K]-?: NonNullable<ObjectResolvers[K]>;
};
/**
* All non-scalar top-level resolvers (i.e. all objects)
*/
type NonScalars<AllResolvers> = {
[K in keyof AllResolvers as NonNullable<AllResolvers[K]> extends GraphQLScalarType ? never : K]: AllResolvers[K];
};
/**
* Results in Then if Object is empty, otherwise results in Else
*/
type IfObjectEmpty<Object, Then, Else> = keyof Object extends never ? Then : Else;
/**
* All object types that have required resolvers
*/
type RequiredObjectResolvers<AllResolvers> = {
[K in keyof NonScalars<AllResolvers> as IfObjectEmpty<
ObjectResolversRequiredFields<NonNullable<AllResolvers[K]>>,
never,
K
>]-?: Override<NonNullable<AllResolvers[K]>, ObjectResolversRequiredFields<NonNullable<AllResolvers[K]>>>;
};
/**
* Make resolvers required for all fields that can't be resolved directly from the backing type
*/
export type ResolversWithMappers<AllResolvers> = Override<AllResolvers, RequiredObjectResolvers<AllResolvers>>; You can use it like this: import {
Resolvers,
} from './generated-types';
import { ResolversWithMappers } from './resolvers-workaround';
export const resolvers: ResolversWithMappers<Resolvers<MyGraphQLContext>> = { /* ... */ }; You'll get a type error (not necessarily an easy to read one) if any resolvers are missing. It'd be really nice to have something like this integrated into the tool itself! It could also probably be a lot less convoluted with some help from the codegen. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
When you enable mappers, there's a strong chance that you forget to define a resolver for a field that's either required in the GraphQL schema, or is a different type from the equivalent field in the mapped type. There doesn't seem to be much that can be done currently to catch this mistake statically!
Some things I tried:
avoidOptionals
just for mapped types - but there's no such optionIt'd be nice to have a straightforward solution for this! Ideally, the generated
Resolvers
type would be smart enough on its own to check for this sort of thing.Beta Was this translation helpful? Give feedback.
All reactions