swc icon indicating copy to clipboard operation
swc copied to clipboard

Decorators failed to resolve metadata type correctly on getter

Open stevefan1999-personal opened this issue 3 years ago • 4 comments

Describe the bug

Ditto to title

Input code

import { Entity } from "typeorm/decorator/entity/Entity"
import { Column } from "typeorm/decorator/columns/Column"
import { PrimaryGeneratedColumn } from "typeorm/decorator/columns/PrimaryGeneratedColumn"

@Entity()
export class Post {
    private _title: string

    @PrimaryGeneratedColumn()
    id: number

    set title(title: string) {
        // this._title = "!" + title + "!"; // if you'll do "append" like this, you won't get expected results, because setter is called multiple times
        if (title === "hello") {
            this._title = "bye"
        } else {
            this._title = title
        }
    }

    @Column()
    get title(): string {
        return this._title
    }
}

Config

{
  "jsc": {
    "externalHelpers": true,
    "keepClassNames": true,
    "parser": {
      "decorators": true,
      "preserveAllComments": true,
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2019",
    "transform": {
      "decoratorMetadata": true,
      "legacyDecorator": true
    },
    "loose": false,
    "minify": {
      "mangle": false,
      "compress": false
    }
  },
  "module": {
    "type": "commonjs"
  },
  "minify": false
}

Playground link

https://play.swc.rs/?version=1.2.218&code=H4sIAAAAAAAAA42Q3UrDQBCF7wN5h3Fv2qKY%2B0qhIOJt30DSZNoO7k%2BYnahB%2Bu7OJqZNpRSXwCbM%2Bc45GXJNYIFvePFC0sERdhwcGOkaDOyKGqvApQQusBcUg87kGY3kc7Ct8zfIqhfEYhBO0Q2TK7l7RY8qxfrfVtdBtc6z9dBwvsgz%2FOpzKlvGCJsQNTLPQE%2FD9KEYvKnS4hKiMPl9otN0fd09OaYx1Uvwrdsij0BEgd5pfuG3GOPSKQqQA8XHIRJWYO4M3A%2BY3vr1lDS0gy60M2uhDmDKpkFfG7D0jj3%2BkKbwGfxMYK%2Bp%2BodYaUNgjK0VnW%2BxKtuIqZMgA0WoSmtV4XROjYYJOYznYpo4%2F%2B200lYHtDaYi%2Brp%2FOm%2B7dCcBUdAq5E3kf6eIMPr8bTzyx3vTxtdjNuc2jNKy36acLLT5we3xAvJ1AIAAA%3D%3D&config=H4sIAAAAAAAAA1WOsW7DMAxE%2F4Wzh6ZbvRXp0KX9B0I%2BG04lUSCZIIaRf6%2BU1DE68t7d8VY6WaB%2BJVwdmjl%2BIhaoUe96Rkc%2FQDlGNvvmhKdaWA3aYgOCKLvsiaKo7IL3GI%2BSErI%2FkS3Z%2BUo9%2BVJgQefi1JFblUaOhls9WCd4tcBeXw5vDStnG0XTv3dfcB7YeauOmDgsHxt%2ByLUvihj%2B6jtKc57HpRUlzlPcQZDUdts2pCaTDOfmWO9r66LqSZJPRre96OH%2BBQMMNOhFAQAA

Expected behavior

Matches the output in official TSC compiler: https://www.typescriptlang.org/play?noEmitHelpers=true&declaration=false&importHelpers=true&target=6&jsx=0&module=1&stripInternal=false&preserveValueImports=false&ts=4.7.4&downlevelIteration=true#code/JYWwDg9gTgLgBAbzgUQHY2DAnnAvnAMyghDgCJswBTaEAegBMqBjaAQxmjqvUyzrQZsZALAAoUJFiI4AYQgAbAK4hUeQsVIUs1WoxbtOUOq2WqAznXlnUoieGjwkABSig2ULAHEeVKByoGaxU1fCISckoaKHomVn8jE0UQy1d3Tx9UPwCg5NU7cQABQT4ACgBKcSoADyl4ZgU2c3M4ZwhzJ3E4brgwNwA3ALgAfSEFKgAuOA63VABzcS6ewrSQD29fBMDg1Qql7uAGKdQVACM-RbEe6ap4MapS+6mZ4HnyxH3ruDo6OBgAC2A5gAdKNMOM4ABecgAQjIcAA1H9wVREbCyABub6-YAEOBYCBKADkCgUcAYEHIbDA1FQDHhCmAAGtUQCgQAafGEuAAdwgqCJ8DmtzgNWozBggTgUCo5iUChg5k552YbCU5lRGpgkqgcCBcFVpKlIHlGDAEIwIFln2uuLgjxRUMh0LI-yopIgZHeCBtX26bJBYJgEJdpywVDsfu6+HdGo+Vyj1wDoPuUORwaovujn1wl2uhR2qD2Ce6wruKIqzxgszm8cTMpgSigamTQfGOfEubEQA

Actual behavior

Emits a wrong type deduction:

_tsDecorate([
    (0, _column.Column)(),
    _tsMetadata("design:type", Function),
    _tsMetadata("design:paramtypes", [])
], Post.prototype, "title", null);

vs

tslib_1.__decorate([
    (0, Column_1.Column)(),
    tslib_1.__metadata("design:type", String),
    tslib_1.__metadata("design:paramtypes", [String])
], Post.prototype, "title", null);

Notice both design:type and design:paramtypes mismatches.

Version

1.2.218

Additional context

Related: #3998

stevefan1999-personal avatar Jul 19 '22 09:07 stevefan1999-personal

Just fyi, we need this feature as well.

gaunap avatar Aug 17 '22 13:08 gaunap

@kdy1 do you have a pointer to get me started on this issue? I grepped for _tsDecorate and can only find TS files so I am not sure where to look for it.

hbina avatar Sep 13 '22 04:09 hbina

@hbina https://github.com/swc-project/swc/tree/d16fb9a8cf8b90fec7fcb224c4da528e8a35bcda/crates/swc_ecma_transforms_proposal/src/decorators contains the decorator transform

kdy1 avatar Sep 13 '22 05:09 kdy1

@stevefan1999-personal Can you elaborate exactly what is expected here? I currently have made this change but after some testing this is not enough.

hbina@akarin ~/g/s/b/swc_cli (main)> git diff -- :/crates/swc_ecma_transforms_proposal/src/decorators/legacy/metadata.rs
diff --git a/crates/swc_ecma_transforms_proposal/src/decorators/legacy/metadata.rs b/crates/swc_ecma_transforms_proposal/src/decorators/legacy/metadata.rs
index 2b526f1b80..078e575043 100644
--- a/crates/swc_ecma_transforms_proposal/src/decorators/legacy/metadata.rs
+++ b/crates/swc_ecma_transforms_proposal/src/decorators/legacy/metadata.rs
@@ -136,8 +136,10 @@ impl VisitMut for Metadata<'_> {
         }
 
         {
-            let dec = self
-                .create_metadata_design_decorator("design:type", quote_ident!("Function").as_arg());
+            let dec = self.create_metadata_design_decorator(
+                "design:type",
+                serialize_type(None, m.function.return_type.as_ref()).into(),
+            );
             m.function.decorators.push(dec);
         }
         {

For example, if you have decorators set for both the getter and setter, tsc will only generate 1 decorator which seems to be a combination of both (function that takes 1 T and return T). Note that you don't need to have the same decorator on both of the getter/setter, one of them is enough.

https://www.typescriptlang.org/play?downlevelIteration=true&noEmitHelpers=true&declaration=false&importHelpers=true&target=6&jsx=0&module=1&stripInternal=false&preserveValueImports=false&ts=4.7.4#code/JYWwDg9gTgLgBAbzgYQgGwK4gHZwL5wBmUEIcARDAJ5gCm0IA9ACa0DG0AhjNIx5jgDOjVAOzkAsAChptAB6RYcNmk6DBcAAoRB8BNLiG4YKMABu3WnAD6MYDDS0AXHF2nsAc2kGjHbG4w2HigACjsHZ1cYdw8ASkQfIyMYAAtgQQA6W3tHOABeOHDHAG5E-G8ZKSSAAVEsbBDYso9aeCLaRpc3YE8EqqSjKFaMKFxU9Iz2srwKmrqcRrLBVsKcjvau6J64voHktMzsiPzViMmIAGUtz0X+wxnKvCA

class Post {
    constructor(title) {
        this._title = title;
    }
    get title() {
        return this.title;
    }
    set title(title) {
        this._title = title.toString();
    }
}
tslib_1.__decorate([
    (0, Column_1.Column)(),
    tslib_1.__metadata("design:type", String),
    tslib_1.__metadata("design:paramtypes", [String])
], Post.prototype, "title", null);

whereas we generate 2 decorators

_tsDecorate([
    (0, _column.Column)(),
    _tsMetadata("design:type", String),
    _tsMetadata("design:paramtypes", [])
], Post.prototype, "title", null);
_tsDecorate([
    (0, _column.Column)(),
    _tsMetadata("design:type", void 0),
    _tsMetadata("design:paramtypes", [
        String
    ])
], Post.prototype, "title", null);

hbina avatar Sep 18 '22 10:09 hbina

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 avatar Oct 03 '22 23:10 swc-bot

Having decorators on both setter and getter seems not to be allowed: "Decorators cannot be applied to multiple get/set accessors of the same name. (1207)". So I guess aborting compilation or ignoring the 2nd decoration and not handling this case should be ok. Could this issue please be reopened?

gaunap avatar Oct 05 '22 09:10 gaunap

Does swc have a separate lint pass?

hbina avatar Oct 05 '22 12:10 hbina

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-bot avatar Nov 05 '22 12:11 swc-bot