Typescript: Decorators not allowed classes expressions

Created on 2 Mar 2016  路  18Comments  路  Source: microsoft/TypeScript

Not sure if this is by design or not, but the following gives a compile error of "Decorators are not valid here" with TypeScript 1.8:

let testClass = new class {
    testMethod(@myDecorator date: Date): any {
        return date;
    }
}();
Committed Decorators Suggestion

Most helpful comment

This also applies when using the new 2.2 mixin design.

I.e.

/** Any type that can construct *something*. */
type Constructor<T> = new (...args: any[]) => T;

function ViewModel<T extends Constructor<MyModel>>(Base: T) {
    return class extends Base {

                // Won't compile. Decorator not allowed here
        @observable
        IsReadOnly: boolean;

                // Won't compile. Decorator not allowed here
        @computed get SomeProp(): string[] {
            return []
        }

        constructor(...args: any[]) {
            super(...args);
            this.IsReadOnly = true
        }
    }
}

Is this something that should work?

All 18 comments

they were never enabled for class expressions. so the behavior has not changed. but they should.

This also applies when using the new 2.2 mixin design.

I.e.

/** Any type that can construct *something*. */
type Constructor<T> = new (...args: any[]) => T;

function ViewModel<T extends Constructor<MyModel>>(Base: T) {
    return class extends Base {

                // Won't compile. Decorator not allowed here
        @observable
        IsReadOnly: boolean;

                // Won't compile. Decorator not allowed here
        @computed get SomeProp(): string[] {
            return []
        }

        constructor(...args: any[]) {
            super(...args);
            this.IsReadOnly = true
        }
    }
}

Is this something that should work?

Not being able to use decorators with the mixin pattern for us means not being able to use the new mixin pattern at all. Is there a new milestone for this?

any movement on this? we're still unable to use the new mixin pattern because of this.

it seems fixable by naming the class but should probably work on anonymous classes too...

If you follow the link above https://github.com/Microsoft/TypeScript/issues/14607, it seems there is a simple work around. The whole problem seems to be that you can't return directly a class with decorators but if you define the class with a local name and then return it everything is good. We have been using that pattern and taking advantage of mixins with decorators.

Just figured out this workaround as well. Here's a simple repro showing where it works and doesn't.

function testDecorator(): PropertyDecorator {
    return function internal() {
        console.log("testing");
    };
}

class Works {
    @testDecorator()
    method(): string {
        return "works";
    }
}

function makeClassWorks() {
    class Generated {
        @testDecorator()
        method(): string {
            return "works";
        }
    }
    return Generated;
}

function makeClassDoesntWork() {
    return class {
        @testDecorator()
        method(): string {
            return "doesn't work";
        }
    };
}
tsc --experimentalDecorators ./test.ts 
narwhal/src/test.ts(26,9): error TS1206: Decorators are not valid here.

I just ran into this. I see it is a future milestone. Any chance it can get scheduled?

I just ran into this also.

My prediction is that we'll tackle this once decorators reach stage 3.

I'd love to get this sooner. We are trying out decorators to write our (Jasmine) unit tests, something like this:

@test.describe
class Foo {
  @test.it
  private someTest() { . . . }
}

but we can't do nested describes.

Hmm... for me the workaround doesn't seem to work, when I export a function:

export function foo() {
  @decorator
  class A { .. }
  return A

Gives:

error TS4060: Return type of exported function has or is using private name

It still doesn't work. Is it ever going to be fixed?

This issue is still active, but with one update, suggested workaround doesn't work anymore. If I do something like

export const testF = () =>
  class Class {
    @Decorator()
    public property: string;
  };

It would complain about decorators with: Decorators are not valid here., while if I try to bypass it as suggested with:

export const testF = () => {
  class Class {
    @Decorator()
    property: string;
  }
  return Class;
};

It would complain about using private property: Exported variable 'testF' has or is using private name 'ButtonStructureItemData'. ts(4025).

Any suggestions or workarounds?

For now, ugly but working, just call your decorators as functions :

class Some {
    @decorate()
    prop: string;
}

becomes

const Some = class {
    prop: string;
}

decorate()(Some.prototype, 'prop');

// (...)

return Some;

@daweedm wouldn't extracting const Some = class {} and then returning that Some again cause same issue as declaring class and returning it back? And if not, why it wouldn't, what's the difference?

I just had the same issue. For documentation purposes, I'll add that this bug concerns the class fields syntax too.

Example:

class RootClass {
  nestedClass = class {
    @decorator
    test() {}
  }
}

Will result in

TS1206: Decorators are not valid here.

Was this page helpful?
0 / 5 - 0 ratings