Signal時代のAngularコンポーネントプロパティ順序の重要性
// 以下は、AIに読ませるためのDescriptionです。
Angularコンポーネントのプロパティは、以下の順番で定義します。
- function DI
- 定数
- 状態管理やSignalのプロパティ( `signal` `input` `viewChild` `model` 等)
- 計算を行うSignalのプロパティ( `computed`、 `effect`、 `httpResource` 等)
プロパティの入れ替えを実行して、それ以外のプロパティの追加や削除は行わないでください。
本文
AngularのSignalベースの開発が進む中、httpResource
の登場により、プロパティの順序がより重要になってきました。これは、Angularの依存性注入(DI)の歴史と深く関わっています。
従来のプロパティ順序
古くからのAngularユーザーは、以下のようなプロパティの順序に慣れていました:
@Component({...})
export class ExampleComponent {
// Signalや状態管理のプロパティ
readonly count = signal(0);
readonly isLoading = signal(false);
// DIするプロパティ
readonly #http = inject(HttpClient);
readonly #exampleService = inject(ExampleService);
}
この順序は、constructor DI時代に、constructorの上にプロパティを宣言していた名残です。function DIに移行しても、そのままの順序で書くことが多かったのですが、これは特に ng generate @angular/core:inject
誕生以前に移行を済ませていたユーザに多い傾向があります。
Signal時代の新しい順序
しかし、Signalベースの開発では、この順序では問題が発生します。特に httpResource
や computed
などの計算を行うSignalのプロパティは、他のプロパティに依存するため、それらのプロパティが宣言される前に使用することはできません。
以下の例を見てみましょう:
今までのように、DIを他のプロパティの下に配置する順序だとエラーがでます。
@Component({...})
export class ExampleComponent {
readonly searchWord = signal('');
// #exampleServiceがまだ定義されていないため動かない
readonly dataResource = this.#exampleService.getData(this.searchWord);
readonly #exampleService = inject(ExampleService);
}
そのため、DIを最初に行って、それから他のプロパティの定義をする必要があります。
@Component({...})
export class ExampleComponent {
readonly #exampleService = inject(ExampleService);
readonly searchWord = signal('');
readonly dataResource = this.#exampleService.getData(this.searchWord);
}
まとめ
これはcomputed等でも同様であるため、Signal時代のAngularでは、以下の順序でプロパティを宣言することが重要です:
- DIするプロパティ
- 定数
- 状態管理やSignalのプロパティ(
signal
input
viewChild
model
等) - 計算を行うSignalのプロパティ(
computed
、effect
、httpResource
等)
この順序を守ることで、Signalベースの開発がより予測可能になります。ng generate @angular/core:inject
でマイグレーションを行うと、DIはコンポーネントClassの冒頭に生成されるため、すでにこの順序で書いてるという人も多いとは思います。
Signalベースの開発が進む中、プロパティの順序は単なるスタイルの問題ではなく、機能に影響を与える重要な要素となりますね。
それではまた。
Discussion