【问题标题】:How does AngularJS2 inject dependencies into my component with TypeScriptAngularJS2 如何使用 TypeScript 将依赖项注入我的组件
【发布时间】:2016-07-01 17:29:37
【问题描述】:

我看到了如何将依赖项注入到我的组件中的各种版本,有些对我有用,有些对我没用。所以我想知道,有什么优点和缺点,推荐的最佳做法是什么,为什么某些没有按预期工作。举个例子:

@Component()
@Injectable()
class MyComponent {

  dependency1: Dependency1;

  constructor(dependency2: Dependency2, dependency3: Dependency3) {
    this.dependency2 = dependency2;
  }

  someFunction() {
    // Which of those will work, which is the best practice,
    //what are pros and cons
    this.dependency1.get();
    this.dependency2.get();
    this.dependency3.get();
  }
}

所以基于这个例子:

  1. 版本 1 (Dependency1) 是否等同于版本 2 (Dependeny2)?还是版本 1 仅适用于 TypeScript,与注入无关?

  2. 是这行代码

    this.dependency2 = dependency2;

这是否需要像 Dependency3 所假设的那样“自动”完成?

  1. Injectable 到底在做什么?如果没有它,问题 1 和 2 的答案会有什么不同?

非常感谢

【问题讨论】:

    标签: dependency-injection typescript angular


    【解决方案1】:

    您似乎在混淆 typescript 参数属性 和 Angular2 DI 机制。

    在使用 typescript 定义构造函数时,基本上有两种选择。简短版:

    @Component()
    class MyComponent {
      constructor(
        public dependency1: Dependency1, 
        public dependency2: Dependency2, 
        public dependency3: Dependency3
      ) { }
    
      // [...]
    

    这将被转换为您也可以使用的更长、更详细的版本:

    @Component()
    class MyComponent {
      public dependency1: Dependency1;
      public dependency2: Dependency2;
      public dependency3: Dependency3;
    
      constructor(
        dependency1: Dependency1, 
        dependency2: Dependency2, 
        dependency3: Dependency3
      ) {
        this.dependency1 = dependency1;
        this.dependency2 = dependency2;
        this.dependency3 = dependency3;
      }
    
      // [...]
    

    这在Typescript Handbook 中有解释。 两者各有利弊,较长的版本对于打字稿新手来说更容易理解和清晰,而后者则节省了很多打字,所以选择你的毒药。 :)

    注意:如果你的类已经有另一个装饰器,则不需要 @Injectable() 装饰器,它仅用于强制通过打字稿生成元数据,它仅适用于装饰类以防止使用不必要的元数据使转译代码膨胀。


    关于 DI 机制,假设您为 Dependency1、Dependency2 和 Dependency3 (1) 导入了定义,注册了它们的提供程序 (2) 并且 angular 创建了组件的实例 (3):

    • someFunction() 内部,this.dependency1 是已声明的(在您的课程开始时公开),并为所有打字稿提供了定义的类型(Dependency1)。但它的当前值是undefined,因为它没有在构造函数中(或其他任何地方)赋值。

      修复dependency1: Dependency1参数添加到构造函数并分配this.dependency1 = dependency1或使用上面的打字稿简写([EDIT] constructor(public dependency1, ...)。

    • 在构造函数中访问this.dependency2 会引发编译错误,因为MyComponent 没有属性dependency2。在不太可能的情况下,这确实会编译/转换,然后 this.dependency2 应该具有正确的值,尽管您将没有 this.dependency2 的类型信息(错误)。

      修复:this.dependency2 的声明添加到您的组件,例如。在构造函数[EDIT]上方添加public dependency2: Dependency2;或在构造函数dependency2参数前面添加public属性constructor(public dependency2, ...)。

    • 最后但同样重要的是this.dependency3 有上述两个问题,没有声明(如dependency2)和undefined 作为值(如dependency1)。

      修复:见上文。 ;)

    注意:了解declaration & definition这是关于 C++,但也适用于打字稿)之间的区别很重要,我希望我做到了打字时不要混淆术语。 ;)


    1. 例如通过:

      import { Dependency1 } from 'dependency-module-1';
      import { Dependency2 } from 'dependency-module-2';
      import { Dependency3 } from 'dependency-module-3';
      
    2. 有多种方法可以为您的依赖项定义提供程序

      • 在引导期间。这使得模块(通过它们的提供者)可用于您应用中的每个组件。

        bootstrap(AppComponent, [
          Dependency1,
          Dependency2,
          Dependency3
        ]);
        
      • 使用组件装饰器。这使得模块可用于 MyComponent 并且相同的模块实例 可用于每个子组件。 如果一个子组件悬停有自己的提供者数组,则会为其生成一个 new 模块实例(就像上面的 shared 与所有子组件一样)。推荐阅读材料是official Angular2 guidethis 博客文章。示例如下:

        @Component({
          providers: [
            Dependency1,
            Dependency2,
            Dependency3
          ]
        })
        class MyComponent {
          \\ [...]
        
    3. 要么 MyComponent 是作为 angulars 引导方法的(第一个)参数传递的,要么是在 DOM 中的某处使用了组件选择器。


    关于最佳实践,您可以尝试使用tslint 和很棒的custom-rule-plugins,例如。 codealyze 是特定于角度的。

    最后但并非最不重要的还有官方 Angular Typescript Styleguide。 ;)

    【讨论】:

    • 非常感谢您的详尽回答。但是,我不确定“在构造函数中访问 this.dependency2 ...”:根据我的理解,这与您所说的短版本转换为长版本的说法相矛盾。还是我错过了什么?
    • 它适用于constructor(public dependency2: Dependency2, dependency3: Dependency3),注意为dependency2 添加的public 参数属性。当您在 MyComponent 的顶部声明 dependency1 时,添加 public 是可选的,但“构造函数扩展”仅在您显式添加 public/private 修饰符时发生,只有那些参数(带有 public /private 修饰符)得到扩展。 (这就是为什么对于 typescript 新手来说,简短版本的可读性较差
    • 对不起,我将这条信息添加到我的原始答案中。 :)
    【解决方案2】:

    请看官方documentation

    也看看这个blog

    Angular 基于constructor based dependency injection。 简而言之,这意味着构造函数参数作为依赖注入。
    Car(e:Engine)

    然后引擎将由汽车实例中的 DI 注入。

    现在您的所有代码都是 Typescript 定义构造函数的方式。以下2个代码是等效的。

    e: Engine Car(e:Engine){ this.e = e }

    Car(public e:Engine){ }

    【讨论】:

    • 我都读过,还有很多其他的(也许这就是问题所在),最佳实践,procs/cons 仍然不清楚
    • 官方准确描述了应该怎么做。
    猜你喜欢
    • 2011-11-22
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 2013-04-10
    • 2017-01-15
    • 2010-10-15
    相关资源
    最近更新 更多