コンポーネント、ディレクティブ、またはパイプが、このコンポーネントによって参照されている場合、コンパイラはインポートを追加する必要があり、インポートの循環が発生します。
たとえば、ParentComponent
がテンプレートでChildComponent
を参照しているシナリオを考えてみます。
parent.component.ts
import {Component} from '@angular/core';import {ChildComponent} from './child.component';@Component({ selector: 'app-parent', imports: [ChildComponent], template: '<app-child/>',})export class ParentComponent {}
child.component.ts
import {Component} from '@angular/core';import {ParentComponent} from './parent.component';@Component({ selector: 'app-child', template: 'The child!',})export class ChildComponent { constructor(private parent: ParentComponent) {}}
ChildComponent
はコンストラクタでParentComponent
を参照しているため、child.component.ts
からparent.component.ts
へのインポートがすでに存在しています。
HELPFUL: 親コンポーネントのテンプレートには<child></child>
が含まれています。
このテンプレートの生成されたコードには、ChildComponent
クラスへの参照を含める必要があります。
この参照を行うために、コンパイラはparent.component.ts
からchild.component.ts
へのインポートを追加する必要があり、これがインポートの循環の原因となります。
parent.component.ts -> child.component.ts -> parent.component.ts
リモートスコープ
NgModuleを使用している場合、循環を作成するインポートを追加しないように、依存関係を接続するコンポーネントが宣言されているNgModule
クラスにコードが追加されます。
これは「リモートスコープ」と呼ばれます。
ライブラリ
残念ながら、「リモートスコープ」コードは副作用があるため、ツリーシェイクが不可能になり、ライブラリでは使用できません。
そのため、"compilationMode": "partial"
設定を使用してライブラリをビルドする場合、循環インポートを必要とするコンポーネントは、このNG3003
コンパイラエラーが発生します。
エラーのデバッグ
生成される循環は、エラーメッセージの一部として表示されます。 たとえば、
コンポーネントChildComponentはテンプレートで使用されていますが、インポートすると循環が発生します。/parent.component.ts -> /child.component.ts -> /parent.component.ts
これを使用して、参照されたコンポーネント、パイプ、またはディレクティブがコンパイルされているコンポーネントにどのように依存しているかを特定します。 問題を解決するためのアイデアをいくつかご紹介します。
- 循環を回避するために、依存関係を再配置してみてください。 たとえば、循環を発生させることなく、両方の依存ファイルにインポートできる独立したファイルに格納されている中間インターフェースを使用します。
- 互いに参照しているクラスを同じファイルに移動して、それらの間でインポートを回避します。
- インポートされた宣言がタイプとしてのみ使用される場合、インポートステートメントをタイプのみのインポート(
import type
構文を使用)に変換します。タイプのみのインポートは循環に寄与しません。