【问题标题】:Dependency injection into abstract class typescript(Angular2)依赖注入抽象类打字稿(Angular2)
【发布时间】:2017-01-06 14:00:19
【问题描述】:

我有抽象类(没有构造函数),我想注入另一个类。

抽象类:

import { ErrorHandler } from '../../shared/services/errorHandler.service';
import { Inject } from '@angular/core';


export abstract class BaseApiComponent<T> {
    @Inject(ErrorHandler) errorHandler: ErrorHandler;

    this.errorHandler.test();
}

注入类:

import { Injectable } from '@angular/core';

@Injectable()
export class ErrorHandler  {
  constructor() { }


  public test() {
    console.log('Test');
  }

}

我还有下一个错误

ORIGINAL EXCEPTION: TypeError: Cannot read property 'test' of undefined

我该如何解决这个问题?

【问题讨论】:

    标签: angular typescript dependency-injection abstract-class


    【解决方案1】:

    从 Angular 2 RC5 开始,DI 变得更简单。你不需要用@Injectable() 来装饰这些东西。相反,您只需在一个地方为 DI 声明它 - NgModule。

    export class ErrorHandler {
        test() {
            console.log('ErrorHandler.test()');
        }
    }
    
    export abstract class BaseApiComponent<T> {
        // use protected property parameter in abstract class
        // for accessibility from descendants.
        constructor(protected errorHandler: ErrorHandler) {}
    
        someMethod() {
            this.errorHandler.test();
        }
    }
    
    export class ApiComponentImpl<T> extends BaseApiComponent<T> {
        // use @Inject decorator
        constructor(@Inject(ErrorHandler) errorHandler: ErrorHandler) {
            super(errorHandler);
        }
    }
    

    app.module.ts

    // class declarations
    @NgModule({
        providers: [
            ErrorHandler,
            ApiComponentImpl
        ]
    })
    export class AppModule{
    }
    
    // bootstrap the app
    platformBrowserDynamic().bootstrapModule(AppModule);
    

    您可以使用 OpaqueToken 来提高模块化并消除类型依赖性:

    export const errorHandlerToken = new OpaqueToken('ErrorHandler');
    

    在模块中:

        providers: [
            // using OpaqueTokens you can change the provided value
            // to anything without changing consumer code 
            {provide: errorHandlerToken, useClass: ErrorHandler},
    

    构造函数:

        constructor(@Inject(errorHandlerToken) errorHandler: ErrorHandler) {
    

    【讨论】:

      【解决方案2】:

      我不是 Angular 开发人员,但在查看示例时,@Inject 装饰器始终用作 parameter decorator 而不是 property decorator

      由于两种装饰器类型不同,这可能会导致问题,但我不确定。
      试试:

      export abstract class BaseApiComponent<T> {
          private errorHandler: ErrorHandler;
      
          protected constructor(@Inject(ErrorHandler) handler) {
              this.errorHandler = handler;
          }
      
          public error() {
              this.errorHandler.test();
          }
      }
      

      另外我不确定你什么时候真正使用this.errorHandler.test();,因为它不能只是坐在课堂上,我把它移到error 方法中。


      编辑

      没错。您需要注入扩展类,然后将实例传递给父类:

      export abstract class BaseApiComponent<T> {
          protected errorHandler: ErrorHandler;
      
          protected constructor(handler: ErrorHandler) {
              this.errorHandler = handler;
          }
      }
      
      export class Restaurants extends BaseApiComponent<any> {
          constructor(@Inject(ErrorHandler) handler) {
              super(handler);
          }
      }
      

      【讨论】:

      • 我继承自 BaseApiComponent 导出类餐厅 extends BaseApiComponent { constructor(private apiService: ApiService) { super();我对这个构造函数有错误:“提供的参数与调用目标的任何签名都不匹配”也许我可以在没有构造函数的情况下注入它?
      • 哦。现在我明白你的意思了。试试我修改后的答案
      【解决方案3】:

      Angular DI 只支持构造函数注入,这意味着你需要一个构造函数。

      您也不能直接注入抽象类,因为抽象类不应该是可实例化的。

      因此它必须是这样的:

      export abstract class BaseApiComponent<T> {
          constructor(errorHandler: ErrorHandler) {}
      
          someMethod() {
           this.errorHandler.test();
          }
      }
      
      export class ApiComponentImpl<T> {
          constructor(errorHandler: ErrorHandler) {
            super(errorHandler);
          }
      
      }
      

      【讨论】:

      • 我不明白为什么。我不太了解 TS,但通常抽象类可以有具体的实现(属性、方法),它们需要被初始化。
      • 有道理。但只是尝试注入一个抽象服务类,因为我想向我的同事展示你不能这样做。这个是用@injecatble 装饰并在根目录中提供的类,它似乎可以工作。你知道为什么吗? stackblitz.com/edit/angular-ivy-nbpvtg?file=src/app/…
      • 有趣的收获。似乎 Angular 不会生成 new Lala(...) 代码,而是通过其他方式创建实例,编译器无法捕捉到抽象类已被实例化。
      猜你喜欢
      • 2019-05-10
      • 2021-09-01
      • 2016-10-26
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      • 2011-05-13
      • 1970-01-01
      相关资源
      最近更新 更多