使用TypeScript在Angular 1.x中的类级可注入依赖项?

时间:2015-10-24 02:16:05

标签: angularjs dependency-injection typescript

对于有点令人费解的标题感到抱歉。

我已经使用Angular 1.x几年了,并且最近一直在研究在代码库中使用TypeScript的可能性(重建方法是在Angular 1.x中)。目前,我在编写类(和类系列)的可注入依赖项时遇到了困难,而不是构造函数的依赖项。

Angular强烈倾向于使用单例服务构建应用程序,但我发现这些单例服务在应用程序运行时的整个生命周期中经常会被过时/不正确的状态污染,或者在应用程序运行时间之间造成不必要的划分。服务及其运行的数据所暴露的功能。

因此,我强烈青睐的一种模式是使用Angular的.factory()生成构造函数,以便在我的应用程序中的各个位置使用。在ES5和Angular的模块系统的上下文中,您可以执行类似的操作:

angular.module('SomeApp', [])
  .factory('BaseClass', baseClassFactory)
  .factory('SubClass', subClassFactory);


baseClassFactory.$inject = ['$http'];
function baseClassFactory ($http) {
  function BaseClass () {}

  BaseClass.prototype = {
    $http: $http
    /* some additional implementation */
  };

  return BaseClass;
}

subClassFactory.$inject = ['BaseClass'];
function subClassFactory (BaseClass) {
  function SubClass () {}

  SubClass.prototype = Object.create(BaseClass.prototype);
  angular.extend(SubClass.prototype, {
    someNewMethod: function () {
      this.$http.get('/some/url').then(function (data) {
        /* some operation on the data to update this instance */
      });
    }
  });

  return SubClass;
}

我现在的重点是,可以创建一个"类"每个人都可以通过工厂函数中的初始化逻辑来访问注入的依赖项。子类的工厂明确地为父类注入工厂的结果;我们被迫利用Angular的模块和dI系统来实现这一目标,但在没有其他东西的情况下,它的效果很好。

在上面的示例中,我可能正在制作一个Model类,其实例公开原始数据以及使用$http保存/删除/使用了什么的操作。在我的应用程序的其他地方,我只需要注入我的一个课程,我可以毫不费力地new SubClass(someArgs).someNewMethod()

在TypeScript(或者,我想,普通的ES6 JS)中,这种模式依赖于Angular模块和可注入组件的运行时依赖性解析,是使用TS / ES6模块的重复工作系统和继承。

对于单例服务或我们希望将依赖项注入构造函数的任何其他类,没有问题。事实上,互联网上有很多例子:

class MyThing {

    static $inject = ['$http'];

    constructor(private $http: ng.IHttpService) {}

}

angular.module('asdf', []).service('myThing', MyThing);

即使对于MyThing的子类,这也很有用。

但是,我没有找到一个好的方法,就是实现我原来的JS例子的效果。理想情况下,我可以声明一些在应用程序中有许多实例的类,但它们仍具有可注入的依赖项。如下所示:

class BaseClass {

    $http: ng.IHttpService;

    constructor(not, injectables) {
        /* i do not exist to be injected */
    }

}

class SubClass extends BaseClass {

    someMethod() {
        return this.$http.get('/some/url');
    }

}

使$http的所有实例都可以使用所需的BaseClass,以及BaseClass的所有实例子类,而无需单调乏味:

angular.module('myModule', [])
    .factory('BaseClass', baseClassFactory)
    .factory('SubClass', subClassFactory)


baseClassFactory.$inject = ['$http'];
function baseClassFactory($http) {
    BaseClass.prototype.$http = $http;
    return BaseClass;
}

subClassFactory.$inject = ['$http'];
function subClassFactory($http) {
    SubClass.prototype.$http = $http;
    return SubClass;
}

当然,这是有效的,但是有很多额外的(容易出错的)样板。它还要求任何子类的作者敏锐地意识到父级指定的每个依赖关系。

我希望这是有道理的。有没有人对如何处理这个问题有任何建议?

1 个答案:

答案 0 :(得分:1)

我认为应该像在ES7中那样以类似的方式处理Typescript:

class BaseClass {

    static $inject = ['$http'];

    constructor(...args) {
        (<any>this).constructor.$inject.forEach((service, index) => {
            this[service] = args[index];
        });
    }
}

这样,孩子可以通过调用super()继承依赖关系或拥有自己的依赖关系。