抽象类打字稿(Angular2)的依赖注入

问题描述 投票:0回答:4

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

抽象类:

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
4个回答
30
投票

从 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) {

17
投票

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

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

因此它必须是这样的:

export abstract class BaseApiComponent<T> {
    constructor(errorHandler: ErrorHandler) {}

    someMethod() {
     this.errorHandler.test();
    }
}

export class ApiComponentImpl<T> {
    constructor(errorHandler: ErrorHandler) {
      super(errorHandler);
    }

}

2
投票

我不是一个有角度的开发人员,但看一下示例,

@Inject
装饰器始终用作参数装饰器,而不是用作属性装饰器

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

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);
    }
}

0
投票

您可以将所需的服务声明为目标抽象类的私有或受保护成员,然后在其构造函数中使用 inject 函数:

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

export abstract class BaseApiComponent<T> {
    
    protected errorHandler: ErrorHandler;

    constructor() {
        this.errorHandler = inject(ErrorHandler);
    }

    testService() {
        this.errorHandler.test();
    }
}

您可以在这个抽象类的实现中使用它:

@Component({...})
export class MyComponentImplementation extends BaseApiComponent<T> {
    override testService() {
        super.testService();
        this.errorHandler.test();
    }
}

此解决方案是一种将依赖项注入抽象类而不触及其实现的方法。

© www.soinside.com 2019 - 2024. All rights reserved.