Skip to content

[typescript-resolvers] Resolvers' default result type should allow async and resolvable object values #7358

Open
@alexstrat

Description

@alexstrat

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreRelated to codegen core/cli

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions