Typescript decorators not unique issues












1















I have the following case, I want to use a decorator to basically change the get of a function, the goal is that the get return if a specific variable has been set or not.



I have the code required to do it but I think I'm not fully understanding how decorators work. I've created the following example on typescript playground: here



function PropertyDecorator(
target: Object, // The prototype of the class
propertyKey: string | symbol // The name of the property
) {
let value = false;

console.log('hit');

return {
get: () => {
return value;
},
set: (val: string) => {
value = val.toLowerCase() !== 'false';
},
enumerable: true,
configurable: true
};
}

class PropertyDecoratorExample {

@PropertyDecorator
name: string;

@PropertyDecorator
name2: string;

constructor() {
console.log('New instance');
console.log(this.name, 'should be false');
this.name = 'hey';
console.log(this.name, 'should be true');
console.log(this.name2, 'should be false');
}
}

new PropertyDecoratorExample();
new PropertyDecoratorExample();


has you can see from the example, the first instance of the object is correct (check the console)
the second instance though, for some reason is keeping the same context as the first one, any ideas why? or what is wrong here?










share|improve this question





























    1















    I have the following case, I want to use a decorator to basically change the get of a function, the goal is that the get return if a specific variable has been set or not.



    I have the code required to do it but I think I'm not fully understanding how decorators work. I've created the following example on typescript playground: here



    function PropertyDecorator(
    target: Object, // The prototype of the class
    propertyKey: string | symbol // The name of the property
    ) {
    let value = false;

    console.log('hit');

    return {
    get: () => {
    return value;
    },
    set: (val: string) => {
    value = val.toLowerCase() !== 'false';
    },
    enumerable: true,
    configurable: true
    };
    }

    class PropertyDecoratorExample {

    @PropertyDecorator
    name: string;

    @PropertyDecorator
    name2: string;

    constructor() {
    console.log('New instance');
    console.log(this.name, 'should be false');
    this.name = 'hey';
    console.log(this.name, 'should be true');
    console.log(this.name2, 'should be false');
    }
    }

    new PropertyDecoratorExample();
    new PropertyDecoratorExample();


    has you can see from the example, the first instance of the object is correct (check the console)
    the second instance though, for some reason is keeping the same context as the first one, any ideas why? or what is wrong here?










    share|improve this question



























      1












      1








      1








      I have the following case, I want to use a decorator to basically change the get of a function, the goal is that the get return if a specific variable has been set or not.



      I have the code required to do it but I think I'm not fully understanding how decorators work. I've created the following example on typescript playground: here



      function PropertyDecorator(
      target: Object, // The prototype of the class
      propertyKey: string | symbol // The name of the property
      ) {
      let value = false;

      console.log('hit');

      return {
      get: () => {
      return value;
      },
      set: (val: string) => {
      value = val.toLowerCase() !== 'false';
      },
      enumerable: true,
      configurable: true
      };
      }

      class PropertyDecoratorExample {

      @PropertyDecorator
      name: string;

      @PropertyDecorator
      name2: string;

      constructor() {
      console.log('New instance');
      console.log(this.name, 'should be false');
      this.name = 'hey';
      console.log(this.name, 'should be true');
      console.log(this.name2, 'should be false');
      }
      }

      new PropertyDecoratorExample();
      new PropertyDecoratorExample();


      has you can see from the example, the first instance of the object is correct (check the console)
      the second instance though, for some reason is keeping the same context as the first one, any ideas why? or what is wrong here?










      share|improve this question
















      I have the following case, I want to use a decorator to basically change the get of a function, the goal is that the get return if a specific variable has been set or not.



      I have the code required to do it but I think I'm not fully understanding how decorators work. I've created the following example on typescript playground: here



      function PropertyDecorator(
      target: Object, // The prototype of the class
      propertyKey: string | symbol // The name of the property
      ) {
      let value = false;

      console.log('hit');

      return {
      get: () => {
      return value;
      },
      set: (val: string) => {
      value = val.toLowerCase() !== 'false';
      },
      enumerable: true,
      configurable: true
      };
      }

      class PropertyDecoratorExample {

      @PropertyDecorator
      name: string;

      @PropertyDecorator
      name2: string;

      constructor() {
      console.log('New instance');
      console.log(this.name, 'should be false');
      this.name = 'hey';
      console.log(this.name, 'should be true');
      console.log(this.name2, 'should be false');
      }
      }

      new PropertyDecoratorExample();
      new PropertyDecoratorExample();


      has you can see from the example, the first instance of the object is correct (check the console)
      the second instance though, for some reason is keeping the same context as the first one, any ideas why? or what is wrong here?







      angular typescript instance decorator






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 15 '18 at 15:00









      Titian Cernicova-Dragomir

      69.3k34865




      69.3k34865










      asked Nov 15 '18 at 14:59









      JoaoglJoaogl

      265




      265
























          1 Answer
          1






          active

          oldest

          votes


















          0














          The problem is that your decorator is invokes exactly once per class per decorated field. So the arrow functions inside the decorator will capture that value variable and will use it for all instances of the decorated class.



          You should not keep instance data in decorator function variables (because as explained above they will be shared) You can keep the data on the current instance which, if you use a regular function, is accessible inside get/set functions using this



          function PropertyDecorator(
          target: Object, // The prototype of the class
          propertyKey: string // The name of the property
          ): any {
          console.log('hit');

          return {
          get: function () {
          return !!this[propertyKey + 'value'];
          },
          set: function(val: string) {
          this[propertyKey + 'value'] = val.toLowerCase() !== 'false';
          },
          enumerable: true,
          configurable: true
          };
          }

          class PropertyDecoratorExample {

          @PropertyDecorator
          name: string;

          @PropertyDecorator
          name2: string;

          constructor() {
          console.log('New instance');
          console.log(this.name, 'should be false');
          this.name = 'hey';
          console.log(this.name, 'should be true');
          console.log(this.name2, 'should be false');
          }
          }

          new PropertyDecoratorExample();
          new PropertyDecoratorExample();





          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53322218%2ftypescript-decorators-not-unique-issues%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            The problem is that your decorator is invokes exactly once per class per decorated field. So the arrow functions inside the decorator will capture that value variable and will use it for all instances of the decorated class.



            You should not keep instance data in decorator function variables (because as explained above they will be shared) You can keep the data on the current instance which, if you use a regular function, is accessible inside get/set functions using this



            function PropertyDecorator(
            target: Object, // The prototype of the class
            propertyKey: string // The name of the property
            ): any {
            console.log('hit');

            return {
            get: function () {
            return !!this[propertyKey + 'value'];
            },
            set: function(val: string) {
            this[propertyKey + 'value'] = val.toLowerCase() !== 'false';
            },
            enumerable: true,
            configurable: true
            };
            }

            class PropertyDecoratorExample {

            @PropertyDecorator
            name: string;

            @PropertyDecorator
            name2: string;

            constructor() {
            console.log('New instance');
            console.log(this.name, 'should be false');
            this.name = 'hey';
            console.log(this.name, 'should be true');
            console.log(this.name2, 'should be false');
            }
            }

            new PropertyDecoratorExample();
            new PropertyDecoratorExample();





            share|improve this answer




























              0














              The problem is that your decorator is invokes exactly once per class per decorated field. So the arrow functions inside the decorator will capture that value variable and will use it for all instances of the decorated class.



              You should not keep instance data in decorator function variables (because as explained above they will be shared) You can keep the data on the current instance which, if you use a regular function, is accessible inside get/set functions using this



              function PropertyDecorator(
              target: Object, // The prototype of the class
              propertyKey: string // The name of the property
              ): any {
              console.log('hit');

              return {
              get: function () {
              return !!this[propertyKey + 'value'];
              },
              set: function(val: string) {
              this[propertyKey + 'value'] = val.toLowerCase() !== 'false';
              },
              enumerable: true,
              configurable: true
              };
              }

              class PropertyDecoratorExample {

              @PropertyDecorator
              name: string;

              @PropertyDecorator
              name2: string;

              constructor() {
              console.log('New instance');
              console.log(this.name, 'should be false');
              this.name = 'hey';
              console.log(this.name, 'should be true');
              console.log(this.name2, 'should be false');
              }
              }

              new PropertyDecoratorExample();
              new PropertyDecoratorExample();





              share|improve this answer


























                0












                0








                0







                The problem is that your decorator is invokes exactly once per class per decorated field. So the arrow functions inside the decorator will capture that value variable and will use it for all instances of the decorated class.



                You should not keep instance data in decorator function variables (because as explained above they will be shared) You can keep the data on the current instance which, if you use a regular function, is accessible inside get/set functions using this



                function PropertyDecorator(
                target: Object, // The prototype of the class
                propertyKey: string // The name of the property
                ): any {
                console.log('hit');

                return {
                get: function () {
                return !!this[propertyKey + 'value'];
                },
                set: function(val: string) {
                this[propertyKey + 'value'] = val.toLowerCase() !== 'false';
                },
                enumerable: true,
                configurable: true
                };
                }

                class PropertyDecoratorExample {

                @PropertyDecorator
                name: string;

                @PropertyDecorator
                name2: string;

                constructor() {
                console.log('New instance');
                console.log(this.name, 'should be false');
                this.name = 'hey';
                console.log(this.name, 'should be true');
                console.log(this.name2, 'should be false');
                }
                }

                new PropertyDecoratorExample();
                new PropertyDecoratorExample();





                share|improve this answer













                The problem is that your decorator is invokes exactly once per class per decorated field. So the arrow functions inside the decorator will capture that value variable and will use it for all instances of the decorated class.



                You should not keep instance data in decorator function variables (because as explained above they will be shared) You can keep the data on the current instance which, if you use a regular function, is accessible inside get/set functions using this



                function PropertyDecorator(
                target: Object, // The prototype of the class
                propertyKey: string // The name of the property
                ): any {
                console.log('hit');

                return {
                get: function () {
                return !!this[propertyKey + 'value'];
                },
                set: function(val: string) {
                this[propertyKey + 'value'] = val.toLowerCase() !== 'false';
                },
                enumerable: true,
                configurable: true
                };
                }

                class PropertyDecoratorExample {

                @PropertyDecorator
                name: string;

                @PropertyDecorator
                name2: string;

                constructor() {
                console.log('New instance');
                console.log(this.name, 'should be false');
                this.name = 'hey';
                console.log(this.name, 'should be true');
                console.log(this.name2, 'should be false');
                }
                }

                new PropertyDecoratorExample();
                new PropertyDecoratorExample();






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 15 '18 at 15:08









                Titian Cernicova-DragomirTitian Cernicova-Dragomir

                69.3k34865




                69.3k34865
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53322218%2ftypescript-decorators-not-unique-issues%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Xamarin.iOS Cant Deploy on Iphone

                    Glorious Revolution

                    Dulmage-Mendelsohn matrix decomposition in Python