Skip to content

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

Open

Description

πŸ”Ž 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

Activity

  1. whzx5byb commented on Sep 15, 2022

    @whzx5byb

    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.

  2. TechQuery commented on Sep 15, 2022

    @TechQuery
    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;
    }
  3. whzx5byb commented on Sep 15, 2022

    @whzx5byb

    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;
    }
  4. TechQuery commented on Sep 15, 2022

    @TechQuery
    Author

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

  5. TechQuery commented on Sep 15, 2022

    @TechQuery
    Author

    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 typescript@4.8.3 in node_modules works fine...

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

  6. whzx5byb commented on Sep 15, 2022

    @whzx5byb

    South Drifter (@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.

  7. HerringtonDarkholme commented on Sep 15, 2022

    @HerringtonDarkholme
    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.

  8. TechQuery commented on Sep 15, 2022

    @TechQuery
    Author

    whzx5byb Thanks your explanation & issue reporting.

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

    Just like #50161 said: sometimes...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: DecoratorsThe issue relates to the decorator syntax

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions