Danilo Lemes
Danilo Lemes

Reputation: 2488

How to properly assign property to function scope?

I've been experimenting Typescript Decorators recently to try solving a "problem" I have within my application. I'm using a JS bridge to feed TS code to both Android and iOS, and at the moment we declare functions like this:

index.js

import foo from './bar'

global.App = function() {
  this.foo = foo;
};

The above will make the foo function to be available on the native side of the bridge

I wanted to write a decorator to apply on that foo method which would "register" itself on the global.App but I've failed in that task.

Here's the decorator that works:

export const Task = (target, propertyKey, descriptor) => {
    let originalMethod = descriptor.value;
    descriptor.value = (...args) => originalMethod.apply(target, args);

    if (!global.App) {
        global.App = function () { 
            this.foo = descriptor.value;
        };
    }
    
    return descriptor;
}

How could I add another method to that global.App function?

Upvotes: 2

Views: 116

Answers (2)

Danilo Lemes
Danilo Lemes

Reputation: 2488

After wandering around SO for some time I've found a workaround for this... perhaps I lack the knowledge of TS/JS to know exactly what I wanted to do here, but anyways, my solution was to register every task decorated and then on the index.js I get those tasks and register them on the global.App function.

Something like this

task.ts

export const TaskRegistry = {};

 export const Task = (target, propertyKey, descriptor) => {
   const originalMethod = descriptor.value;
   descriptor.value = (...args) => originalMethod.apply(target, args);

   TaskRegistry[propertyKey] = descriptor.value;

   return descriptor;
 };

index.js

// eslint-disable-next-line func-names
global.App = function () {
   // eslint-disable-next-line consistent-this
   const self = this;

   Object.keys(TaskRegistry).forEach((key) => {
     self[key] = TaskRegistry[key];
   });
}

Upvotes: 1

VeryGoodDog
VeryGoodDog

Reputation: 335

Firstly, the foo method is only added once because the first time the decorator is called global.App is defined and the branch that adds foo to global.App is never re-entered.

Secondly, global.App and foo would be overwritten each time and not maintained through repeated calls to the decorator.

Adding another branch that handles adding the method after the first call and dynamically assigns the name of the method, which I believe is given to the decorator in propertyKey, would permit multiple methods to be added.

export const Task = (target, propertyKey, descriptor) => {
    let originalMethod = descriptor.value;
    descriptor.value = (...args) => originalMethod.apply(target, args);

    if (!global.App) {
        global.App = function () { 
            this[propertyKey] = descriptor.value;
        };
    } else {
        global.App[propertyKey] = descriptor.value;
    }
    
    return descriptor;
}

Something like this might work.

Upvotes: 1

Related Questions