依赖注入库 - 重命名注入的值

Ale*_*lls 7 javascript dependency-injection node.js typescript ecmascript-next

我想通过名字注入lodash,如下所示:

let val = function(lodash){
   // lodash will be injected, simply by using require('lodash');
};
Run Code Online (Sandbox Code Playgroud)

但是说我要重命名导入,我想做这样的事情:

let val = function({lodash:_}){

};
Run Code Online (Sandbox Code Playgroud)

要么

let val = function(lodash as _){

};
Run Code Online (Sandbox Code Playgroud)

有没有办法用ES6/ES7/ES8或TypeScript做到这一点?

请注意,这个DI框架比仅需要('x')做更多的工作......它将首先尝试注入其他值,如果没有其他值,那么它将尝试要求该值.

另请注意,这里的要求是当您调用val.toString()时,"lodash"将被视为参数名称.但是在函数体内的运行时会看到_而不是lodash.这是因为为了注入lodash,我们调用fn.toString()来获取参数名称.

Pat*_*rts 5

更新

这里是npm包di-proxy的链接(灵感来自这个答案),具有100%的代码覆盖率,并支持memoization以提高性能,与Node.js兼容>=6.0.0.

老答案

这里是一个真棒解决方案,我想通了,而摆弄周围物体拆解Proxy:

/* MIT License */
/* Copyright 2017 Patrick Roberts */
// dependency injection utility
function inject(callbackfn) {
  const handler = {
    get(target, name) {
      /* this is just a demo, swap these two lines for actual injection */
      // return require(name);
      return { name };
    }
  };
  const proxy = new Proxy({}, handler);

  return (...args) => callbackfn.call(this, proxy, ...args);
}

// usage

// wrap function declaration with inject()
const val = inject(function ({ lodash: _, 'socket.io': sio, jquery: $, express, fs }, other, args) {
  // already have access to lodash, no need to even require() here
  console.log(_);
  console.log(sio);
  console.log($);
  console.log(express);
  console.log(fs);
  console.log(other, args);
});

// execute wrapped function with automatic injection
val('other', 'args');
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper {
  max-height: 100% !important;
}
Run Code Online (Sandbox Code Playgroud)

这个怎么运作

通过对象解构将参数传递给函数会调用对象文字上每个属性的getter方法,以便在执行函数时确定值.

如果要解析的对象初始化为a Proxy,则可以使用对尝试解析的属性名称的引用来拦截每个getter调用,并返回您选择使用的值来解析它.在这种情况下,分辨率应该是require(name),只需在函数对象参数中将其指定为属性名称即可注入模块.

下面是一个演示的链接,您可以在其中实际看到它在Node.js中工作.

在线尝试!

这是该演示中的代码仅供参考,因为它在更大程度上演示了对象解构:

/* MIT License */
/* Copyright 2017 Patrick Roberts */
// dependency injection utility
function inject(callbackfn) {
  const handler = {
    get(target, name) {
      return require(name);
    }
  };
  const proxy = new Proxy({}, handler);

  return (...args) => callbackfn.call(this, proxy, ...args);
}

// usage

// wrap function declaration with inject()
const val = inject(function ({
  fs: { readFile: fsRead, writeFile: fsWrite },
  child_process: { fork: cpF, spawn: cpS, exec: cpE },
  events: { EventEmitter }
}, other, args) {
  // already have access to modules, no need to require() here
  console.log('fs:', { fsRead, fsWrite });
  console.log('child_process:', { fork: cpF, spawn: cpS, exec: cpE });
  console.log('EventEmitter:', EventEmitter);
  console.log(other, args);
});

// execute wrapped function with automatic injection
val('other', 'args');
Run Code Online (Sandbox Code Playgroud)

如上所述,我已经发布了一个完整的npm包来实现这个概念.如果您喜欢这种语法,我建议您查看它,并希望比这个非常基本的示例更具性能和测试性.