swc icon indicating copy to clipboard operation
swc copied to clipboard

design:type wrong for enum values

Open hcesar opened this issue 5 years ago • 34 comments
trafficstars

Describe the bug In TSC, when you have an enum type, the base enum type is set as design:type. SWC is setting the enum object itself.

Input code

enum MyEnum {
  x = "xxx",
  y = "yyy"
}

class Xpto {
  @Decorator()
  value!: MyEnum;
}

function Decorator() {
  return function (...args) {};
}

Config

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

Expected behavior A clear and concise description of what you expected to happen.

TSC:

__decorate([
    Decorator(),
    __metadata("design:type", String)
], Xpto.prototype, "value", void 0);

SWC:

Reflect.metadata("design:type", typeof MyEnum === "undefined" ? Object : MyEnum)

hcesar avatar Oct 12 '20 12:10 hcesar

@kdy1 Any news regarding this issue ? We have a similar problem that's preventing our team from switching to swc. We're using https://github.com/RobinBuschmann/sequelize-typescript and decorators are a problem for us right now.

@Column
status: TProcessingStates;

TSC:

__decorate([
    decorators_1.Groups([{ operation: 'read' }, { operation: 'write' }]),
    sequelize_typescript_1.Column,
    __metadata("design:type", String)
], Collage.prototype, "status", void 0);

SWC:

Reflect.metadata("design:type", typeof _mediaManager.TProcessingStates === "undefined" ? Object : _mediaManager.TProcessingStates)

Switching to swc would be a game changer for our team.

Exilz avatar Dec 03 '20 13:12 Exilz

@Exilz I'll fix this soon.

I expect today or tomorrow (It's almost 11 PM here, so...)

kdy1 avatar Dec 03 '20 13:12 kdy1

Fixed it.

May I list your company on the site as swc user after the migration?

kdy1 avatar Dec 03 '20 20:12 kdy1

@kdy1 I need to ask the CEO permission but I guess we'd be happy to be listed on the website ! How do I go about testing your fix ? Do I need to build the source myself ? I've never used rust before so I'm not sure where to start.

EDIT: nevermind, I just realized you have a CI that's compiling it right now.

Exilz avatar Dec 03 '20 20:12 Exilz

@Exilz I'm now in progress of publishing. Github actions will publish new version. Typically it takes about one hour.

Oh. I noticed that github updates comments real-time.

kdy1 avatar Dec 03 '20 20:12 kdy1

@kdy1 thanks a lot for the update. I'm still in the process of refactoring our code, but it looks like we're one step closer to migrating to swc.

However, I noticed a couple of things :

  • Using enums as the issue stated, it doesn't work if the enum is imported from another file. It compiles properly when the enum is declared in the same file, though.

import { TPublicationStatus } from '../publicationStatus'; 

class MyClass {

  @Column
   publicationStatus: TPublicationStatus;
}

which compiles to

_dec31 = typeof Reflect !== "undefined" && typeof Reflect.metadata === "function" && Reflect.metadata("design:type", typeof _publicationStatus.TPublicationStatus === "undefined" ? Object : _publicationStatus.TPublicationStatus)
  • A kind of related issue happens using types instead of enums, as in the following exemple :
    @Column
    type: 'reps' | 'time';

which compiles to

 _dec24 = typeof Reflect !== "undefined" && typeof Reflect.metadata === "function" && Reflect.metadata("design:type", void 0)

This is also true when declaring the type separately and not directly in the class.

Should I open a new issue ? Or two ?

Exilz avatar Dec 03 '20 21:12 Exilz

I'll just reopen this. But I'm not sure if knowing a type is enum without evaluating dependencies. (tsc works by loading all file, while swc and babel work in one-by-one manner)

Evaluating deps is not hard, but I'm not sure about the api change.

kdy1 avatar Dec 03 '20 21:12 kdy1

@kdy1 I understand what you mean, this is quite a big change for the project as a whole. However, I guess importing a type or an enum and using it like this is a common usage, right ?

If this isn't implemented, you'd need to document it and make sure people are aware of this because it's quite "sneaky", and the errors it can generate when running your app won't make sense to most people.

Maybe that's something the maintainers need to discuss further.

Exilz avatar Dec 03 '20 22:12 Exilz

I don't think it's sneaky. Why it's sneaky? It is just misunderstanding about the way tools work.

kdy1 avatar Dec 03 '20 22:12 kdy1

Well, because something that's working within a single file will break when using imports. Sneaky isn't quite the right word, but it will probably confuse people.

Exilz avatar Dec 03 '20 23:12 Exilz

I believe this single file limitation will be a deal breaker for most people interested in SWC.

If SWC can't be a transparent replacement for TSC, there will be just very few use cases where it will be used.

hcesar avatar Dec 04 '20 10:12 hcesar

I'm actively working on the type system, which will allow any transforms requiring type informations.

Even though the issue can be fixed by simple hack, I'm not sure if it's correct way to go. It requires lots of opinionated approach.

kdy1 avatar Dec 04 '20 10:12 kdy1

Would appreciate a simple hack first (or as an option) since type system is a long way to go.

sunnylqm avatar Feb 22 '21 09:02 sunnylqm

I agree with @sunnylqm, we've been eager to hop on the swc train ever since we've discovered it, but this issue is still a show stopper for us. @kdy1 Do you have any rough timeline regarding the availability of the type system ? Or maybe the aforementioned hack ?

Exilz avatar Feb 22 '21 09:02 Exilz

@Exilz No. I don't have one.

kdy1 avatar Feb 22 '21 10:02 kdy1

I have questions regarding the issue.

For the context, I want to implement this for the next version but this is fairly complex, mainly due to circular imports. Also, as it is also used by deno, there are some restrictions in the APIs.

To support it correctly, loader abstraction and a caching layer are required.

So my first question is

  • Are you guys using spack?

It already have loader abstraction and a caching layer, so it would be easier.

Also, I'm not sure about the api. The api of swc is designed after babel, which handles one file at a time. But tsc compiles all dependencies even if the user only passes one file.

I think flags like --deps (and jsc.includeDeps: true in .swcrc) would work.

  • Does this API seem reasonable?

If not, please feel free to tell me.

kdy1 avatar Mar 04 '21 10:03 kdy1

@kdy1 We're not using spack. Our setup is fairly simple so using only the CLI is enough for us. I guess it would be acceptable for you to require people to use your bundler in order to achieve such things as long as it's clearly stated in the documentation.

The deps flag / includeDeps option would be awesome. I'm just wondering if it should be enabled by default.

Exilz avatar Mar 04 '21 13:03 Exilz

Is includeDeps equivalent to isolatedModules?

sunnylqm avatar Mar 04 '21 15:03 sunnylqm

@sunnylqm No. The purpose of the option is to prevent breaking things. e.g. npx swc src/ should work identically. But with includeDeps: true, the invocation can be changed to npx swc src/index.ts.

kdy1 avatar Mar 04 '21 15:03 kdy1

Compiling one by one is always a compromise for babel. If swc aims to work the same way as tsc then why not. Shouldn't swc eventually become a full feature drop in replacement?

sunnylqm avatar Mar 04 '21 15:03 sunnylqm

I think the option is enough for tsc mode (or project mode) vs babel mode.

Eventually, I'll add the ability to run babel plugins without modification. (See https://github.com/swc-project/swc/pull/1416)

kdy1 avatar Mar 04 '21 15:03 kdy1

I've implemented the very basics of multi-file decorator metadata support, but I'm not sure how much I should implement. Currently, I tested only export enum Foo, and there's no code to support enum Foo with export { Foo }, nor codes for handling circular imports.

How do you guys think about it?

kdy1 avatar Apr 17 '21 10:04 kdy1

We can try some alpha versions to see if it can solve some problems

sunnylqm avatar Apr 17 '21 13:04 sunnylqm

@kdy1 hello and thanks for the awesome product! It works amazing, but we bumped into the same issue with decorator metadata, while trying to adopt SWC in the company. I see that it's been moved into Blocked by type checker milestone. Is the type-checking feature has been planned to be implemented in any foreseeable future? Thanks.

kdubrovnyi avatar May 06 '22 18:05 kdubrovnyi

I think this can be fixed without the type checker. The main problem is internal apis, though.

kdy1 avatar May 07 '22 06:05 kdy1

Does this work for tsc with isolatedmodules?

kdy1 avatar May 07 '22 07:05 kdy1

@kdy1 thanks for the reply.

Just checked, the project has no errors when running tsc with --isolatedModules switch. With swc though, the decorator metadata for imported enum has been generated in a way that won't work with TypeOrm - throws an error in runtime (the same as specified in the issue).

Of course, if this can be fixed, it will help a great deal to move our project to use swc. Thanks!

kdubrovnyi avatar May 07 '22 14:05 kdubrovnyi

Encountering the same issue with sequelize-typescript, everything else is working perfectly but without Sequelize we can't run the app or @swc-node/jest tests

mfcodeworks avatar Jun 01 '22 15:06 mfcodeworks

Encountering the same issue with sequelize-typescript, everything else is working perfectly but without Sequelize we can't run the app or @swc-node/jest tests

See if this typeorm sidestep I made is somehow portable to sequelize. Essentially there were infered enum types that did not work and needed to be explicitly set

drFabio avatar Jun 01 '22 15:06 drFabio

Encountering the same issue with sequelize-typescript, everything else is working perfectly but without Sequelize we can't run the app or @swc-node/jest tests

See if this typeorm sidestep I made is somehow portable to sequelize. Essentially there were infered enum types that did not work and needed to be explicitly set

Thanks, it did actually prevent one error from popping up, I'll see if applying this to all enum types solves the issue

mfcodeworks avatar Jun 02 '22 09:06 mfcodeworks