nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
66.9k stars 7.55k forks source link

Can't resolve dependencies with consistent type imports #13721

Closed hywax closed 2 months ago

hywax commented 2 months ago

Is there an existing issue for this?

Current behavior

Now there is a bug, when we do import type, then nest can't resolve dependencies. This is erroneous behavior because from a typescript point of view everything is correct, we are using the class as a type, not an instance.

If you write the code:

- import { HealthCheckService, HealthCheckResult } from '@nestjs/terminus';
+ import type { HealthCheckService, HealthCheckResult } from '@nestjs/terminus';

import { HealthCheck } from '@nestjs/terminus';
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly health: HealthCheckService) {}

  @Get()
  @HealthCheck()
  check(): Promise<HealthCheckResult> {
    return this.health.check([
      () => ({ info: { status: 'up', message: 'Everything is fine' } }),
    ]);
  }
}

Then we get:

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

Minimum reproduction code

https://stackblitz.com/edit/nestjs-typescript-starter-yejp4i?file=src%2Fapp.controller.ts

Steps to reproduce

No response

Expected behavior

There shouldn't be an error

Package

Other package

No response

NestJS version

No response

Packages versions

{
"dependencies": {
    "@nestjs/common": "^10.3.2",
    "@nestjs/core": "^10.3.2",
    "@nestjs/platform-express": "^10.3.2",
    "@nestjs/terminus": "^10.2.3",
    "reflect-metadata": "^0.2.1",
    "rxjs": "^7.8.1"
  },
  "devDependencies": {
    "@nestjs/cli": "^10.3.1",
    "@nestjs/schematics": "^10.1.0",
    "@nestjs/testing": "^10.3.2",
    "@swc/cli": "^0.3.9",
    "@swc/core": "^1.4.0",
    "@types/express": "^4.17.21",
    "@types/jest": "^29.5.12",
    "@types/node": "^20.11.16",
    "@types/supertest": "^6.0.2",
    "@typescript-eslint/eslint-plugin": "^6.21.0",
    "@typescript-eslint/parser": "^6.21.0",
    "eslint": "^8.56.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.1.3",
    "jest": "^29.7.0",
    "prettier": "^3.2.5",
    "source-map-support": "^0.5.21",
    "supertest": "^6.3.4",
    "ts-jest": "^29.1.2",
    "ts-loader": "^9.5.1",
    "ts-node": "^10.9.2",
    "tsconfig-paths": "^4.2.0",
    "typescript": "^5.3.3"
  }
}

Node.js version

20.9.0

In which operating systems have you tested?

Other

No response

jmcdo29 commented 2 months ago

This is a fault of Typescript, because when import type is used, the resulting compiled JavaScript doesn't have the import of the original type, as Typescript will strip the type imports, and then it will cause the metadata that Nest relies on to not be accurate/existent. There's nothing Nest can really do about this either, as it's a language feature, not a framework one.

It's important to note that while it looks like you're using the imported class as a type, it's actually being used as a reference when the metadata is properly set. You'd need to view the compiled JS to understand that though