👻

Angular v20のResources APIの変更点まとめ:エラー処理の改善とAPIの整理

に公開

Angular Resourcesの実装が次のリリースでどのように変更されるかについて、GitHubの議論スレッドと関連コミットからの情報に基づいて共有します。

Angular Resourcesは実験中APIであり、これらのリリース後もv20段階では実験中のままを予定されてるので、今後も変更されていく可能性があることにはご注意ください。

1. エラー処理の改善

Resource.value()の振る舞いの変更

以前はリソースがエラー状態の場合、 resource.value()undefined を返していました。しかし、新しい実装では、リソースがエラー状態の際に resource.value() を読み取ると例外がスローされるようになります。
この変更により、エラーを明示的に扱う必要が出てきます。

以前の振る舞い:デフォルトでエラーが隠蔽されていた

const res = resource({
  loader: () => fetch(...);
});

// 変更前(エラーが隠蔽される)
const inner = computed(() => res.value()?.inner);

新しい振る舞い:明示的にエラーを処理する必要がある

const res = resource({
  loader: () => fetch(...);

  // 変更案1: Errorsではなく、defaultValue(初期値はundefined)を返すようにする
  throwErrorsFromValue: false,
});

// 変更案2: errorのハンドリングを行う
const inner = computed(() => {
  if (res.error()) return undefined;
  return res.value()?.inner;
});

テンプレートでのエラー処理

これはもちろんHTMLテンプレートにおいても同様です。resource.value() をオプショナル値で使っていた場合、 isLoading だけではなく、エラーの確認も行うようにする必要がありますね。

@if (res.isLoading()) {
  <!-- ローディング中のコンテンツ -->
} @else if (res.error()) {
  <!-- エラー時のコンテンツ -->
} @else {
  <!-- 正常時のコンテンツ -->
}

ちなみに、振る舞いの詳細でいうと以下の感じです。

  • エラーの状態でリロードを行うと、 hasValue()true になって、 value()defaultValue が返されるようになる
  • 新しい値が正常にロードされると、 error()undefined になる

Resource.errorの型の明確化

Resource.errorの型がunknownからError | undefinedに変更され、型安全なエラーハンドリングが可能になります。

const error = resource.error();
if (error instanceof Error) {
  // error.message など型安全にアクセス可能
}

型ガードを使ったエラー処理が書きやすくなりますね。あと、細かい話になりますが、Error以外の値がthrowされた場合もResourceWrappedErrorでラップされるため、エラーの一貫した扱いが可能になりました。

if (resource.error() instanceof ResourceWrappedError) {
  const original = resource.error().cause;
  // originalがAPIのエラーオブジェクトなど
}

https://github.com/angular/angular/blob/d3e9ca1162a0d72e78708fcce5644b9b25e4d487/packages/core/src/resource/resource.ts#L469-L478

2. reload()メソッドの移動

reload()WritableResourceのみで使えるようになり、「リロード可能なリソース」と「読み取り専用リソース」を明確に分けて設計できるようになります。

const res = resource<Data>({
  loader: () => fetch(...), 
});

// WritableResourceなので、`reload`メソッドにアクセスできる
res.reload();

// Writableでないため`reload`メソッドにアクセスできない
res.asReadonly();
res.reload(); // NG

3. パラメータ名の変更

requestからparamsに変更され、より意図が明確な名前に変更されます。

// 変更前
const res = resource<User>({
  request: () => ({id: userId()}),
  loader: ({request}) => {
    return this.http.get<User>(`/api/users/${request.id}`);
  }
});

// 変更後
const res = resource<User>({
  params: () => ({id: userId()}),
  loader: ({params}) => {
    return this.http.get<User>(`/api/users/${params.id}`);
  }
});

また、httpResourceも、静的URLではなく、関数を渡すようになりました。

const userId = signal(1);
const res = httpResource<User>(() => `/api/users/${userId()}`);

まとめ

他にも、 httpResource では map 関数が parse 関数にリネームされてたりと上記がすべてではありませんが、リリース前に「こうやって変わるんだ」と待ち構える手助けになりましたら幸いです。

The Resource story in Angular is just starting and will be evolving. To reflect this, the resource APIs will remain experimental in Angular v20. We will persuade the stabilization process and embark on designing additional APIs and functionality in the subsequent releases. Your continued feedback is crucial: play with Angular v20, build on top of it and open GitHub issues for any problems or enhancements that should be considered.from discussioncomment-12654043

Angular における Resource の取組は始まったばかりで、今後進化していきます。それを反映し、Resource API は Angular v20 において引き続き「実験的(experimental)」な状態のままとなります。私たちは安定化プロセスを進めるとともに、今後のリリースで追加の API や機能の設計にも取り組んでいきます。皆さんからの継続的なフィードバックは非常に重要です。ぜひ Angular v20 を試して、実際に使ってみてください。そして問題点や改善点があれば、GitHub に Issue を立てて知らせてください。

とのことで、今後もより安全に使いやすくなっていく進化が楽しみですね。

それではまた。

Discussion