Skip to content Skip to sidebar Skip to footer

Generic Reading Of Arguments From Multiple Constructor Calls

Follow-up question to Read arguments from constructor call: The accepted solution allows me to get arguments passed into a constructor by defining a wrapper class that captures and

Solution 1:

Yes, you can create generic wrapper which will add args property to instance of any passed constructor:

class Plugin {
  constructor (arg1, arg2) {
    this.arg1 = arg1
    this.arg2 = arg2    
  }
}

function wrapper(initial) {
  // Rewrite initial constructor with our function
  return function decoratedContructor(...args) {
    // Create instance of initial object
    const decorated = new initial(...args)

    // Add some additional properties, methods
    decorated.args = [...args]

    // Return instantiated and modified object
    return decorated
  }
}

const decoratedPlugin = wrapper(Plugin)
const plugin = new decoratedPlugin('argument', { 'argument2': 1 })
console.log(plugin.args)

FYI: it's not safe to add properties without some prefix. Consider adding __ or something like this to your property, because you can accidentally rewrite some inner object property.


Solution 2:

I was able to get this working with a modification to @guest271314's suggestion, namely, you need to pass ...initArgs to super(), otherwise webpack will fail with a TypeError: Cannot read property '...' of undefined.

Also took @terales's point into account about making sure to prefix my additional properties.

const exposeConstructorArgs = (Plugin, ...args) => {
  const ExposedPlugin = class extends Plugin {
    constructor(...initArgs) {
      super(...initArgs);

      this.__initArgs__ = initArgs;
    }

    get __initArgs() {
      return this.__initArgs__;
    }
  };

  return Reflect.construct(ExposedPlugin, args);
};

// ...

const dllPlugin = exposeConstructorArgs(webpack.DllPlugin, {
  name: '[name]',
  path: path.join(buildDir, '[name].json'),
});

// ...

const pluginConfig = dllPlugin.__initArgs[0];

expect(pluginConfig.name).toEqual('[name]');

Solution 3:

You can use a generic function where class expression is used within function body. Pass reference to the class or constructor and parameters expected to be arguments within the instance to the function call.

function Plugin() {}

function Plugin2() {}

function PluginWrapper(pluginRef, ...args) {
  let MyPlugin = class extends pluginRef {
    constructor() {
      super();
      this.args = [...arguments];
    }
    getArgs() {
      return this.args;
    }
  }
  return Reflect.construct(MyPlugin, args);
};

const anInstance = PluginWrapper(Plugin, {
  a: 'path'
});

console.log(anInstance.getArgs(), anInstance instanceof Plugin);

const aSecondInstance = PluginWrapper(Plugin2, "arg1", "arg2", {
  b: 'anotherPath'
});

console.log(aSecondInstance.getArgs(), aSecondInstance instanceof Plugin2);

Post a Comment for "Generic Reading Of Arguments From Multiple Constructor Calls"