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

[Bug] Mixin parameters failed to use as Method Parameter types of Inner Classes #50792

Open
TechQuery opened this issue Sep 15, 2022 · 8 comments
Labels
Bug A bug in TypeScript
Milestone

Comments

@TechQuery
Copy link

TechQuery commented Sep 15, 2022

πŸ”Ž Search Terms

mixin, parameter, class method, type declaration, decorator

πŸ•— Version & Regression Information

  • This is a crash
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about mixin & parameter

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

const register: MethodDecorator = () => { }

const validate: ParameterDecorator = () => { }

function mixin<T>(Model: new (...data: any[]) => T) {
    class Trait {
        @register
        method(@validate input: Model) { }
    }
    return Trait;
}

class TestModel {
    id = 0
}

class TestController extends mixin(TestModel) { }

πŸ™ Actual behavior

Type checking crashed

error TS2749: 'Model' refers to a value, but is being used as a type here. Did you mean 'typeof Model'?

         method(@validate input: Model) {
                                 ~~~~~

Compiled seems to work

function mixin(Model) {
    var _a;
    class Trait {
        method(input) { }
    }
    __decorate([
        register,
        __param(0, validate),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [typeof (_a = typeof Model !== "undefined" && Model) === "function" ? _a : Object]),
        __metadata("design:returntype", void 0)
    ], Trait.prototype, "method", null);
    return Trait;
}

πŸ™‚ Expected behavior

Shown sample code works, so that projects with Decorator frameworks will be much simpler, like what my service scaffold does: idea2app/REST-Node-ts#1

@whzx5byb
Copy link

The error message is correct. Model refers to a value of a function parameter and you should use typeof to refer to the type of it.
See https://www.typescriptlang.org/docs/handbook/2/typeof-types.html.

@TechQuery
Copy link
Author

The error message is correct. Model refers to a value of a function parameter and you should use typeof to refer to the type of it. See https://www.typescriptlang.org/docs/handbook/2/typeof-types.html.

I know that typeof is the "correct syntax", but if I change it like that, Parameter Decorator will failed to get emited classes:

const register: MethodDecorator = () => { }

const validate: ParameterDecorator = () => { }

function mixin<T>(Model: new (...data: any[]) => T) {
    class Trait {
        @register
-        method(@validate input: Model) { }
+        method(@validate input: typeof Model) { }
    }
    return Trait;
}

class TestModel {
    id = 0
}

class TestController extends mixin(TestModel) { }
function mixin(Model) {
    var _a;
    class Trait {
        method(input) { }
    }
    __decorate([
        register,
        __param(0, validate),
        __metadata("design:type", Function),
-        __metadata("design:paramtypes", [typeof (_a = typeof Model !== "undefined" && Model) === "function" ? _a : Object]),
+        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], Trait.prototype, "method", null);
    return Trait;
}

@whzx5byb
Copy link

I think this workaround should work:

function mixin<T>(Model: new (...data: any[]) => T) {
+    type Model = typeof Model;
    
    class Trait {
        @register
        method(@validate input: Model) { }
    }
    return Trait;
}

@TechQuery
Copy link
Author

@whzx5byb Thanks your hack code, but I wonder that class syntax is both type & value, why should I use typeof in mixins?

@TechQuery
Copy link
Author

TechQuery commented Sep 15, 2022

@whzx5byb If I use both type & value of classes, your hack code shows a type error in my VS Code 1.71.0:

- const register: MethodDecorator = () => { }
+ const register: (Model: new (...data: any[]) => any) => MethodDecorator =
    () => () => { }

const validate: ParameterDecorator = () => { }

function mixin<T>(Model: new (...data: any[]) => T) {
+    type Model = typeof Model;

    class Trait {
-        @register
+        @register(Model)
        method(@validate input: Model) { }
    }
    return Trait;
}

class TestModel {
    id = 0
}

class TestController extends mixin(TestModel) { }
ts[2502] Model is referenced directly or indirectly in its own type annotation. 

but tsc compiling with the same [email protected] in node_modules works fine...

TS playground & GitPod's VS Code 1.69.2 works fine, too...

@whzx5byb
Copy link

whzx5byb commented Sep 15, 2022

@TechQuery

why should I use typeof in mixins?

A class declaration does create value and type entities but a variable only create the value one. In your case Model is just a variable refers to the class, so it doesn't create a type entity.

If I use both type & value of classes, your hack code shows a type error in my VS Code 1.71.0

I believe this is a bug, which is similar to #50191 and #50161. I have reported it in #50795.

@HerringtonDarkholme
Copy link
Contributor

Minimal reproduction.

const A: new() => any = class B {}
function validate(...a: any[]) {}
class B {
    @validate test(a: typeof A) {}
}

compiles to

image

It looks like the behavior of typeof Expr is not handled properly in decorator metadata.

@TechQuery
Copy link
Author

@whzx5byb Thanks your explanation & issue reporting.

When I open my GitPod VS Code again, the same error hints...

Just like #50161 said: sometimes...

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Sep 22, 2022
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Sep 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants