当服务包含彼此时访问静态属性时出错

时间:2018-01-06 02:11:39

标签: angular typescript

按原样运行以下代码时,会出现此错误:

Uncaught TypeError: Cannot read property 'TYPE_CAMPAIGN' of undefined

Plunker Example

entity.service.ts

import {Injectable} from '@angular/core';
import {CampaignService} from './campaign/campaign.service';
import {TagService} from './tag/tag.service';

@Injectable()
export class EntityService {
  static TYPES = [
    CampaignService.TYPE_CAMPAIGN,
    TagService.TYPE_TAG
  ];
}

campaign.service.ts

import {Injectable} from '@angular/core';
import {EntityService} from '../entity.service';

@Injectable()
export class CampaignService {
  static TYPE_CAMPAIGN = 'campaign';

  constructor(private entityService: EntityService) {}

  public getTypes() {
    return EntityService.TYPES;
  }
}

tag.service.ts

import {Injectable} from '@angular/core';
import {EntityService} from '../entity.service';

@Injectable()
export class TagService {
  static TYPE_TAG = 'tag';

  constructor(private entityService: EntityService) {}
}

但是,当我从campaign.service.ts中删除构造函数时,代码可以正常运行。为什么会出现错误,如何在包含构造函数时访问静态属性?

更新1:在使用Angular的Injector进行测试以在加载类时进行偏移后,我发现在CampaignService的方法中访问EntityService的静态属性时仍然存在问题。我还发现在private entityService: EntityService中添加campaign.service.ts会导致问题。

更新2:问题是由提供服务的模块中的import语句的顺序引起的(我最近按字母顺序排列了我的导入语句)。

app.module.ts

import {CampaignService} from './campaign/campaign.service';
import {EntityService} from '../entity.service';
import {TagService} from './tag/tag.service';

@NgModule({
  providers: [
    CampaignService,
    EntityService,
    TagService
  ]
});

entity.service.ts的导入语句在campaign.service.ts之前移动时,CampaignService和TagService都可以正常运行。

更新3:看起来问题是特定于版本的。以下是我目前使用的版本中发生问题的示例:Example

如果您在观看控制台时切换src/app.component.ts中的导入语句,那么您将看到手头的问题。

1 个答案:

答案 0 :(得分:1)

可能是注射器决定是否有循环参考。看一下代码,我不会指望它,因为只有一个服务有一个构造函数。但是,您描述的行为指向此。

您可以尝试注射注射器并通过勾选延迟注射过程 见Angular2: 2 services depending on each other

@Injectable()
export class CampaignService {
  static TYPE_CAMPAIGN = 'campaign';
  private entityService;

  constructor(injector: Injector) {
    setTimeout(() => this.entityService = injector.get(EntityService));
  }
}

在campaign.service.ts

中使用EntityService.TYPES

希望这涵盖了您的用例。 这是我的StackBlitz

<强> campaign.service.ts

import {Injectable, Injector} from '@angular/core';
import {EntityService} from './entity.service';

@Injectable()
export class CampaignService {
  static TYPE_CAMPAIGN = 'campaign';
  private entityService;
  types = EntityService.TYPES;

  constructor(private injector: Injector) {
    setTimeout( () => this.entityService = injector.get(EntityService) );
  }
}

<强> app.component.ts

import { Component } from '@angular/core';
import {EntityService} from './entity.service';
import {CampaignService} from './campaign.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';
  types = EntityService.TYPES;

  constructor(
    private entityService: EntityService, 
    private campaignService: CampaignService
  ) { }
}

<强> app.component.html

<hello name="{{ name }}"></hello>
<p>
  Start editing to see some magic happen :)
</p>
<div> Types from EntityService {{ types }} </div>
<div> Types from campaignService {{ campaignService.types }} </div>