Search code examples
typescriptnestjstsc

Nest dependency resolution issue with tsconfig paths and barrel files/same directory imports


I've set a few different paths in tsconfig.json to make importing of controllers, entities, services, etc. easier to deal with. Relevant portion of tsconfig.json:

...
"baseUrl": "./src",
"paths": {
  "@hello/controllers": [
    "./controllers"
  ],
  "@hello/entities": [
    "./entity"
  ],
  "@hello/services": [
    "./services"
  ]
},
...

I've also created barrel files (index.ts) within the src/controllers/, src/entity/, and src/services/ directories that re-exports all of the classes that I need from within those directories.

Everything works as expected when importing a service from a file that is within my controllers directory. Example:

// src/controllers/comment.controller.ts
// This works
import { CommentService } from '@hello/services';

@Controller()
export class CommentController {...}

Things do NOT work when importing a service from another service file that is within the same directory. Example

// src/services/comment.service.ts
// This does NOT work
import { StoryService, UserService } from '@hello/services';
// StoryService, UserService, and CommentService are in the src/services directory 

@Injectable()
export class CommentService {...}

The error that I get when doing the above is:

Error: Nest can't resolve dependencies of the CommentService (?, +). Please make sure that the argument at index [0] is available in the AppModule context.

Expected behavior I expect dependencies to resolve using a path defined in tsconfig.json, even if they're being imported from within the same directory.

Possible Solution My current workaround is to import the files using relative paths:

// src/services/comment.service.ts
// This does work
import { StoryService } from './story.service';
import { UserService } from './user.service';
// I'd prefer to do this:
// import { StoryService, UserService } from '@hello/services';

@Injectable()
export class CommentService {...}

Environment @nestjs/common@5.7.4 @nestjs/core@5.7.4 typescript@3.6.2

Update My index.ts barrel file in src/services is shown below:

// src/services/index.ts
export * from './comment.service';
export * from './story.service';
export * from './user.service';

Solution

  • EXPORT ORDER MATTERS

    In my index.ts barrel file, I was exporting the comment service before the user and story services. However, the comment.service.ts class imports story.service.ts and user.service.ts. Story and user must be exported BEFORE comment.

    Before:

    // src/services/index.ts
    // This does NOT work 
    // and throws the "Nest can't resolve dependencies of the CommentService..." error
    export * from './comment.service';
    export * from './story.service';
    export * from './user.service';
    

    After with correct ordering:

    // src/services/index.ts
    // This works!
    export * from './story.service';
    export * from './user.service';
    export * from './comment.service';
    

    Now I can use the import path in my tsconfig.json in the comment service:

    import { StoryService, UserService } from '@hello/services';
    
    @Injectable()
    export class CommentService {...}
    

    Thanks to @ford04 for hinting to the issue being in index.ts.