Graphql: InterfaceType with resolveType => TypeError: Cannot read property 'type' of undefined

Created on 29 Jul 2020  路  6Comments  路  Source: nestjs/graphql

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior


After being able to use interfaces (see https://github.com/nestjs/graphql/issues/1062), I have a new error when I try to use a resolveType function. Regarding the NestJS documentation I've configured my InterfaceType as follow :

@InterfaceType({
  resolveType: (character)=> {
    if (character.totalCredits) {
      return Human;
    } else {
      return Droid;
    }
  },
})

When I try to run the app I get :

(node:5529) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'type' of undefined
    at /Users/cedric/Documents/Lab/Nest-test/node_modules/@nestjs/graphql/dist/schema-builder/factories/object-type-definition.factory.js:49:128
    at Array.map (<anonymous>)
    at /Users/cedric/Documents/Lab/Nest-test/node_modules/@nestjs/graphql/dist/schema-builder/factories/object-type-definition.factory.js:49:60
    at resolveThunk (/Users/cedric/Documents/Lab/Nest-test/node_modules/graphql/type/definition.js:478:40)
    at defineInterfaces (/Users/cedric/Documents/Lab/Nest-test/node_modules/graphql/type/definition.js:684:37)
    at GraphQLObjectType.getInterfaces (/Users/cedric/Documents/Lab/Nest-test/node_modules/graphql/type/definition.js:639:31)
    at collectReferencedTypes (/Users/cedric/Documents/Lab/Nest-test/node_modules/graphql/type/schema.js:361:61)
    at new GraphQLSchema (/Users/cedric/Documents/Lab/Nest-test/node_modules/graphql/type/schema.js:148:9)
    at GraphQLSchemaFactory.<anonymous> (/Users/cedric/Documents/Lab/Nest-test/node_modules/@nestjs/graphql/dist/schema-builder/graphql-schema.factory.js:40:28)
    at Generator.next (<anonymous>)

Expected behavior


I would like to use the resolveType function as it is describe in the documentation GraphQL + TypeScript - Interfaces

Minimal reproduction of the problem with instructions


Repository: https://github.com/maniolias/nest-test/tree/feature/interface
Branch: feature/interface

Run npm run start:dev

What is the motivation / use case for changing the behavior?


In the provided repository there is no need of resolveType function. But I'm working on another project where we use business specific entities which aren't related to NestJS but they share interfaces. The resolveType function would be a good solution to avoid conversion from business entities to presentation entities.

Environment


Nest version: 7.4.0
Nest graphql version: 7.6.0


For Tooling issues:
- Node version: 12.18.1  
- Platform:  Mac 

Others:

Workaround

After hours of analysing the code I figured out that if we put the interface and every types that implements it in the same file it works. But it's not an ideal solution if we have a lot of types to deal with.

Most helpful comment

I had the same problem. Finally,I found the reason.

reason

If we divide ObjectType and InterfaceType into different files, the order of autoSchemaFile may be wrong .
In this case, ObjectType will be generated before InterfaceType.
Then, the params of ObjectType would become { implements:[ undifind ] }.

Workaround

Use require.
Or, Generated all InterfaceType before ObjectType ?

// import { User } from 'src/models/user.model';
// import { Post } from 'src/models/post.model';

@InterfaceType({
  resolveType(value) {
    if ('name' in value) {
      const { User } = require('src/models/user.model');
      return User
    } else if ('title' in value) {
      const { Post } = require('src/models/post.model');
      return Post;
    } else return NodeRecord;
  },
})
export abstract class Node {
  @Field(type => ID)
  id: string;
}

All 6 comments

I had the same problem. Finally,I found the reason.

reason

If we divide ObjectType and InterfaceType into different files, the order of autoSchemaFile may be wrong .
In this case, ObjectType will be generated before InterfaceType.
Then, the params of ObjectType would become { implements:[ undifind ] }.

Workaround

Use require.
Or, Generated all InterfaceType before ObjectType ?

// import { User } from 'src/models/user.model';
// import { Post } from 'src/models/post.model';

@InterfaceType({
  resolveType(value) {
    if ('name' in value) {
      const { User } = require('src/models/user.model');
      return User
    } else if ('title' in value) {
      const { Post } = require('src/models/post.model');
      return Post;
    } else return NodeRecord;
  },
})
export abstract class Node {
  @Field(type => ID)
  id: string;
}

@intVergil Thank you SO MUCH for the require-workaround. I spent countless hours trying to figure out what was wrong - I would never have figured this solution out - it works perfectly!

Passing an arrow function that returns an array of interfaces, as shown below:

image

should fix this issue. I've updated the documentation https://docs.nestjs.com/graphql/interfaces#code-first

Hi Kamil,

Thank you very much for the updated docs, however that approach is what I already used. The issue is in the resolver, not in the implementation of the interface, where it is currently not possible to return a class, unless it is imported using require. If properly import'ed, you get the issue.

Here's a simplified example from my own code:

```
import { Field, InterfaceType, registerEnumType } from "@nestjs/graphql";
//import { StructureFieldTextModel } from "./structure-field-text.model"; // 鈥硷笍 won't work
//import { StructureFieldDateModel } from "./structure-field-date.model"; // 鈥硷笍 won't work

@InterfaceType({
resolveType: (field) => {
switch(field.fieldType) {
case 'text':
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { StructureFieldTextModel } = require('./structure-field-text.model'); // 鈥硷笍 only working approach
return StructureFieldTextModel;
case 'date':
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { StructureFieldDateModel } = require('./structure-field-date.model'); // 鈥硷笍 only working approach
return StructureFieldDateModel;
}
}
})
export abstract class StructureFieldModel {
@Field()
ID: string;

// ... shortened
}

After I bumped to latest version of @nest dependencies, I was able to resolve this issue @bitnissen

I have the same issue. Actually even the require does not work for me. I had to include the definitions in the same file.

Was this page helpful?
0 / 5 - 0 ratings