Dev Study
← Angular コース

46. toSignal と toObservable — 2つの世界の橋渡し

Angularには「時間とともに届く値」を扱うRxJSの世界と、「今の値」を扱うシグナルの世界があります。@angular/core/rxjs-interop の toSignal と toObservable は、この2つを行き来する橋です。toSignal(obs$) はObservableをシグナルに変換し、値が届くたびにシグナルが更新されます。逆に toObservable(sig) はシグナルの変化をObservableの流れとして取り出します。

実務でよく使うのは、HttpClientが返すObservableを toSignal でシグナルにする形です。テンプレートでは users() と普通のシグナルとして読むだけでよく、asyncパイプもsubscribeも不要になります。逆方向の toObservable は、検索語のシグナルを流れに変えて switchMap につなぐなど、「シグナルの変化をきっかけに通信したい」場面で活躍します。

つまずきやすいのは初期値です。Observableは最初の値が届くまで何も持たないため、toSignal(obs$, { initialValue: [] }) のように initialValue を指定しないと、シグナルの型に undefined が混ざります。テンプレートで配列として扱うなら空配列を初期値にしておくのが定番です。また、toSignal は購読の解除を自動で行うため、コンポーネントのフィールド初期化などDIコンテキストの中で呼ぶ必要があります。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';

type User = { id: number; name: string };

@Component({
  selector: 'app-user-list',
  // シグナルなので users() と呼び出すだけ。async パイプも不要
  template: '@for (user of users(); track user.id) { <p>{{ user.name }}</p> }',
})
export class UserListComponent {
  private http = inject(HttpClient);

  // Observable をシグナルに変換。届くまでは initialValue の空配列
  users = toSignal(this.http.get<User[]>('/api/users'), {
    initialValue: [] as User[],
  });
}
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗