Description
Is your feature request related to a problem? Please describe.
Without mappers
, when resolving an object of which some values are promises instead of plain values, typing reports errors while the GraphQL execution is fine (GraphQL default resolver even accepts a resolve function as value and supports promise values).
type BarConnection {
totalCount: Int!
edges: [BarEdge!]!
}
type Foo {
bars: BarConnection!
}
type LazyBarConnection = {
totalCount: Promise<number>;
edges: Promise<BarEdge[]>;
}
const makeConnection = (): LazyBarConnection => {...}
const resolvers: Resolvers = {
Foo: {
// Types of property 'totalCount' are incompatible.
// Type 'Promise<number>' is not assignable to type 'number'.
bars: () => makeConnection()
}
}
Describe the solution you'd like
By default, defaultMapper
should be Resolvable<T>
where Resolvable
looks like this:
type MaybeInPromise<ValueType> = ValueType | Promise<ValueType>
type MaybeAsFuncResultOrPromise<ValueType> =
| ValueType
| MaybeInPromise<ValueType>
// todo: explicit parameters typing
| ((...args: unknown[]) => MaybeInPromise<ValueType>)
type ResolvableArray<ArrayType> = {
[Key in keyof ArrayType]: Resolvable<ArrayType[Key]>
}
type ResolvableObject<ObjectType> = {
[Key in keyof ObjectType]: MaybeAsFuncResultOrPromise<Resolvable<ObjectType[Key]>>
}
export type Resolvable<ValueType> = ValueType extends Array<any>
? ResolvableArray<ValueType>
: ValueType extends {}
? ResolvableObject<ValueType>
: MaybeInPromise<ValueType>
(Extracted from this comment)
Describe alternatives you've considered
I successfully use the option defaultMapper
to wrap object types in a Resolvable<T>
, but the purpose of this issue is to make this behavior the default one because that's what GraphQL default execution would accept.
Additional context
#1219 started mentioning the issue and #1593 resulted in more options that allows alternative solutions.