Avoid circular dependency when using interface in Nestjs/GraphQL

Viewed 313

I was following the code first approach to defining a GraphQL interface in the Nestjs docs.

However, the resolveType() requires that you return a class instance and forces me to import the classes that implements the interface (I have the classes in different files); this creates circular depedencies amongst my classes and the interface files.

Example:

book.interface.ts:

import { ColoringBook } from './coloring-book.model.ts
import { TextBook } from './textbook.model.ts

@InterfaceType(resolveType(book) {
   if (book.colors) {
      return ColoringBook;
   }
   return Textbook;
})
abstract class Book {
   // class members...
}

coloring-book.model.ts:

import { Book } from './book.interface.ts';

@ObjectType({ implements: Book})
class ColoringBook implements Book {
  // class members...
}

textbook.model.ts:

import { Book } from './book.interface.ts';

@ObjectType({ implements: Book})
class Textbook implements Book {
  // class members...
}

I've tried this like:

resolveType(book) {
    if (book.colors) {
      return forwardRef(() => ColoringBook);
    }
    return forwardRef(() => TextBook);
}

but that doesn't help as I still need to import the class and it doesn't actually resolve at runtime.

What would be a best practice way of avoiding this circular dependency short of consolidating everything to one file?

2 Answers

I ended up following how it was done here:

@InterfaceType({
  resolveType: value => value.constructor.name,
})

I am not sure if this has any side effects underlying but it definitely looks cleaner and doesn't require me to circular import.

Building on your answer:

It seems like you can simply pass the class name instead of the JS class, which results in:

book.interface.js

// no import

@InterfaceType(resolveType(book) {
   if (book.colors) {
      return 'ColoringBook';
   }
   return 'Textbook';
})
abstract class Book {
   // class members...
}

In my case, value.constructor.name was systematically the Interface name (Book instead of <Specifier>Book)

Related