Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot access before initialization error in NestJs #6498

Closed
michaeldesigaud opened this issue Nov 22, 2022 · 15 comments
Closed

Cannot access before initialization error in NestJs #6498

michaeldesigaud opened this issue Nov 22, 2022 · 15 comments

Comments

@michaeldesigaud
Copy link

michaeldesigaud commented Nov 22, 2022

Describe the bug

I'm using swc in a NestJs project and i'm facing the following issue when i run my unit test with jest:

ReferenceError: Cannot access 'DocumentEntity' before initialization

      10 |
      11 | @Entity('documents')
    > 12 | export class DocumentEntity extends EntityObj {
         |              ^
      13 |   @PrimaryGeneratedColumn()
      14 |   id: string;
      15 |

      at Object.DocumentEntity (features/documents/document.entity.ts:12:14)
      at Object.<anonymous> (features/documents/data/document-data.entity.ts:16:14)
      at Object.<anonymous> (features/documents/document.entity.ts:12:29)
      at Object.<anonymous> (features/resources/resource.entity.ts:13:25)
      at Object.<anonymous> (features/resources/resources-db.store.ts:10:25)
      at Object.<anonymous> (features/resources/resources-db.store.spec.ts:5:27)

I think the error is caused by the automapper library which i use in the document-data.entity.ts:

Input code

@Entity('documents-data')
export class DocumentDataEntity {
  @PrimaryColumn()
  @AutoMap()
  key: string;

  @PrimaryColumn({ nullable: false })
  documentId?: string;

  @AutoMap(() => DocumentEntity) // Think error comes from here
  document?: DocumentEntity;
}

Config

{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true,
      "dynamicImport": true
    },
    "target": "es2021",
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    }
  },
  "module": {
    "type": "commonjs",
    "noInterop": false
  }
}

FYI, it works with the swc config "target": "es5" but then i've got code coverage issues

Playground link

No response

Expected behavior

I'm expecting the test to run correctly

Actual behavior

No response

Version

1.13.19

Additional context

No response

@weyert
Copy link

weyert commented Nov 30, 2022

I am having the same issue without using Nestjs but I do have a decorator on the constructor of my class. I will try to make a reproducible case. For me it also improves things when switching back to targetting es5

@michael-dm
Copy link

michael-dm commented Nov 30, 2022

For anyone having the problem with NestJS, using ModuleRef on one end of the circular definition solves it.
See here : https://docs.nestjs.com/fundamentals/module-ref

@dustin-rcg
Copy link

dustin-rcg commented Dec 2, 2022

I am getting the same error after upgrading swc. I am using ts-node with swc, via my tsconfig.json

  "ts-node": {
    "swc": true
  },

This error is happening pretty much everywhere there is a typescript reference to a class type. For example, in my entity class, the fields will reference typescript types of other entity classes.

It seems to be a problem with the loader not understanding that these are merely type references and not instances of the class object. I can remove the error by the following, but I have to do it all throughout my code base!

Create a trivial typescript type

type Type<T> = T;

Then change all my class type references from Foo to Type<Foo>. For example, if I have a field such as

todos: Todo[];

then it becomes

todos: Type<Todo>[];

When I do this, the circular dependency is resolved. It seems to force the class reference to be treated as just a type, rather than an actual class object instance. Very strange,

@dustin-rcg
Copy link

dustin-rcg commented Dec 3, 2022

Maybe this is just #5047 . I sure would like to know what magic makes Type<T> work, and why swc can't do that without the wrapper type.

@timofei-iatsenko
Copy link

@dustin-rcg do you have decorators on that classes? With decorators and "decoratorMetadata": true SWC have to inline a type info into the transformed file, and what is from your perspective looks like "type only usage" from SWC perspective would be referencing to type constructor. BTW typescript doing the same, but indeed there are differences.
I think differences in how SWC vs TS generating exports / import, order may be?

I also have the same issues in GraphQL models and looking how to resolve it.

@timofei-iatsenko
Copy link

I've created a related issue in NestJS Graphql Repo nestjs/graphql#2568

@allanvobraun

This comment was marked as spam.

@lucas-silveira

This comment was marked as spam.

1 similar comment
@antonphilin

This comment was marked as spam.

@fknop
Copy link

fknop commented Feb 19, 2023

Maybe this is just #5047 . I sure would like to know what magic makes Type<T> work, and why swc can't do that without the wrapper type.

This is definitely due to this, I think SWC should understand that the import is used as a type and not a value. I don't know if that's possible.
We also encountered this issue and adding Type<T> everywhere is not a great option for us.

@Xiot
Copy link

Xiot commented Feb 21, 2023

I just ran into this as well, while attempting to migrate a NestJS app from ts-jest to @swc/jest

The issue is a heart caused by a circular dependency, but its also how swc handles it, as ts-jest worked.

This is the relevant parts from the output of ts-jest

// require statements are here
let TeamTasksService = TeamTasksService_1 = class TeamTasksService { ... }
// rest of code
exports.default = TeamTasksService;

The same file transformed with swc produces

Object.defineProperty(exports, "default", {
    enumerable: true,
    get: ()=>TeamTasksService
});
// require statements are here
let foo = require('./foo') // which references this file

// rest of code

The error is surfaced because this file is part of a circular dependency so the default export is getting referenced before this file has had a chance to finish parsing.

@magic-akari
Copy link
Member

Maybe this is just #5047 . I sure would like to know what magic makes Type<T> work, and why swc can't do that without the wrapper type.

This is definitely due to this, I think SWC should understand that the import is used as a type and not a value. I don't know if that's possible. We also encountered this issue and adding Type<T> everywhere is not a great option for us.

Is it really being imported as type ?

If so, import type { Foo } from "foo" might be a good solution.
ref: https://www.typescriptlang.org/docs/handbook/modules.html#importing-types

importsNotUsedAsValues: "error" will make it easier for you to spot this issue.
ref: https://www.typescriptlang.org/tsconfig/#importsNotUsedAsValues

With an eslint rule this can be fixed automatically.
ref: https://typescript-eslint.io/rules/consistent-type-imports/

Note:

The emitDecoratorMetadata compiler option changes the code the TypeScript emits. In short - it causes TypeScript to create references to value imports when they are used in a type-only location.

ref: https://typescript-eslint.io/rules/consistent-type-imports/#usage-with-emitdecoratormetadata

If the above is true, I don't think this is an easy fix.

@micalevisk
Copy link

micalevisk commented Feb 25, 2023

@magic-akari I did that but still got the same error due to how the generated js file looks like. I'm not using with jest but swc+node directly. My project has some circular imports (typeorm stuff).

@swc-bot swc-bot added the Stale label Mar 30, 2023
@swc-bot
Copy link
Collaborator

swc-bot commented Apr 1, 2023

This issue has been automatically closed because it received no activity for a month and had no reproduction to investigate. If you think this was closed by accident, please leave a comment. If you are running into a similar issue, please open a new issue with a reproduction. Thank you.

@swc-bot swc-bot closed this as completed Apr 1, 2023
@swc-bot
Copy link
Collaborator

swc-bot commented May 2, 2023

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@swc-project swc-project locked as resolved and limited conversation to collaborators May 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests