Skip to content

Commit d8ca560

Browse files
alxhubmmalerba
authored andcommitted
refactor(core): convert ResourceStatus to a string type (angular#60919)
An outcome of the Resource RFC was that we should use string constants for communicating the resource status instead of an enum. This commit converts `ResourceStatus` accordingly. PR Close angular#60919
1 parent b1bfb21 commit d8ca560

File tree

6 files changed

+95
-135
lines changed

6 files changed

+95
-135
lines changed

adev/src/content/guide/signals/resource.md

+10-11
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ The `ResourceLoaderParams` object contains three properties: `request`, `previou
4747
| `previous` | An object with a `status` property, containing the previous `ResourceStatus`. |
4848
| `abortSignal` | An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal). See [Aborting requests](#aborting-requests) below for details. |
4949

50-
51-
If the `request` computation returns `undefined`, the loader function does not run and the resource status becomes `Idle`.
50+
If the `request` computation returns `undefined`, the loader function does not run and the resource status becomes `'idle'`.
5251

5352
### Aborting requests
5453

@@ -100,15 +99,15 @@ The resource object has several signal properties for reading the status of the
10099
| `isLoading` | Whether the resource loader is currently running. |
101100
| `status` | The resource's specific `ResourceStatus`, as described below. |
102101

103-
The `status` signal provides a specific `ResourceStatus` that describes the state of the resource.
102+
The `status` signal provides a specific `ResourceStatus` that describes the state of the resource using a string constant.
104103

105-
| Status | `value()` | Description |
106-
| ----------- | :---------------- | ---------------------------------------------------------------------------- |
107-
| `Idle` | `undefined` | The resource has no valid request and the loader has not run. |
108-
| `Error` | `undefined` | The loader has encountered an error. |
109-
| `Loading` | `undefined` | The loader is running as a result of the `request` value changing. |
110-
| `Reloading` | Previous value | The loader is running as a result calling of the resource's `reload` method. |
111-
| `Resolved` | Resolved value | The loader has completed. |
112-
| `Local` | Locally set value | The resource's value has been set locally via `.set()` or `.update()` |
104+
| Status | `value()` | Description |
105+
| ------------- | :---------------- | ---------------------------------------------------------------------------- |
106+
| `'idle'` | `undefined` | The resource has no valid request and the loader has not run. |
107+
| `'error'` | `undefined` | The loader has encountered an error. |
108+
| `'loading'` | `undefined` | The loader is running as a result of the `request` value changing. |
109+
| `'reloading'` | Previous value | The loader is running as a result calling of the resource's `reload` method. |
110+
| `'resolved'` | Resolved value | The loader has completed. |
111+
| `'local'` | Locally set value | The resource's value has been set locally via `.set()` or `.update()` |
113112

114113
You can use this status information to conditionally display user interface elements, such loading indicators and error messages.

goldens/public-api/core/index.api.md

+1-8
Original file line numberDiff line numberDiff line change
@@ -1638,14 +1638,7 @@ export interface ResourceRef<T> extends WritableResource<T> {
16381638
}
16391639

16401640
// @public
1641-
export enum ResourceStatus {
1642-
Error = 1,
1643-
Idle = 0,
1644-
Loading = 2,
1645-
Local = 5,
1646-
Reloading = 3,
1647-
Resolved = 4
1648-
}
1641+
export type ResourceStatus = 'idle' | 'error' | 'loading' | 'reloading' | 'resolved' | 'local';
16491642

16501643
// @public
16511644
export type ResourceStreamingLoader<T, R> = (param: ResourceLoaderParams<R>) => PromiseLike<Signal<ResourceStreamItem<T>>>;

packages/common/http/src/resource.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,7 @@ class HttpResourceImpl<T>
301301
});
302302

303303
readonly headers = computed(() =>
304-
this.status() === ResourceStatus.Resolved || this.status() === ResourceStatus.Error
305-
? this._headers()
306-
: undefined,
304+
this.status() === 'resolved' || this.status() === 'error' ? this._headers() : undefined,
307305
);
308306
readonly progress = this._progress.asReadonly();
309307
readonly statusCode = this._statusCode.asReadonly();

packages/core/src/resource/api.ts

+20-40
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,29 @@ import {Signal, ValueEqualityFn} from '../render3/reactivity/api';
1111
import {WritableSignal} from '../render3/reactivity/signal';
1212

1313
/**
14-
* Status of a `Resource`.
14+
* String value capturing the status of a `Resource`.
15+
*
16+
* Possible statuses are:
17+
*
18+
* `idle` - The resource has no valid request and will not perform any loading. `value()` will be
19+
* `undefined`.
20+
*
21+
* `loading` - The resource is currently loading a new value as a result of a change in its reactive
22+
* dependencies. `value()` will be `undefined`.
23+
*
24+
* `reloading` - The resource is currently reloading a fresh value for the same reactive
25+
* dependencies. `value()` will continue to return the previously fetched value during the reloading
26+
* operation.
27+
*
28+
* `error` - Loading failed with an error. `value()` will be `undefined`.
29+
*
30+
* `resolved` - Loading has completed and the resource has the value returned from the loader.
31+
*
32+
* `local` - The resource's value was set locally via `.set()` or `.update()`.
1533
*
1634
* @experimental
1735
*/
18-
export enum ResourceStatus {
19-
/**
20-
* The resource has no valid request and will not perform any loading.
21-
*
22-
* `value()` will be `undefined`.
23-
*/
24-
Idle,
25-
26-
/**
27-
* Loading failed with an error.
28-
*
29-
* `value()` will be `undefined`.
30-
*/
31-
Error,
32-
33-
/**
34-
* The resource is currently loading a new value as a result of a change in its `request`.
35-
*
36-
* `value()` will be `undefined`.
37-
*/
38-
Loading,
39-
40-
/**
41-
* The resource is currently reloading a fresh value for the same request.
42-
*
43-
* `value()` will continue to return the previously fetched value during the reloading operation.
44-
*/
45-
Reloading,
46-
47-
/**
48-
* Loading has completed and the resource has the value returned from the loader.
49-
*/
50-
Resolved,
51-
52-
/**
53-
* The resource's value was set locally via `.set()` or `.update()`.
54-
*/
55-
Local,
56-
}
36+
export type ResourceStatus = 'idle' | 'error' | 'loading' | 'reloading' | 'resolved' | 'local';
5737

5838
/**
5939
* A Resource is an asynchronous dependency (for example, the results of an API call) that is

packages/core/src/resource/resource.ts

+19-29
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@ export function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T |
6868
);
6969
}
7070

71-
type ResourceInternalStatus =
72-
| ResourceStatus.Idle
73-
| ResourceStatus.Loading
74-
| ResourceStatus.Resolved
75-
| ResourceStatus.Local;
71+
type ResourceInternalStatus = 'idle' | 'loading' | 'resolved' | 'local';
7672

7773
/**
7874
* Internal state of a resource.
@@ -114,9 +110,7 @@ abstract class BaseWritableResource<T> implements WritableResource<T> {
114110
this.set(updateFn(untracked(this.value)));
115111
}
116112

117-
readonly isLoading = computed(
118-
() => this.status() === ResourceStatus.Loading || this.status() === ResourceStatus.Reloading,
119-
);
113+
readonly isLoading = computed(() => this.status() === 'loading' || this.status() === 'reloading');
120114

121115
hasValue(): this is ResourceRef<Exclude<T, undefined>> {
122116
return this.value() !== undefined;
@@ -181,13 +175,12 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
181175
source: this.extRequest,
182176
// Compute the state of the resource given a change in status.
183177
computation: (extRequest, previous) => {
184-
const status =
185-
extRequest.request === undefined ? ResourceStatus.Idle : ResourceStatus.Loading;
178+
const status = extRequest.request === undefined ? 'idle' : 'loading';
186179
if (!previous) {
187180
return {
188181
extRequest,
189182
status,
190-
previousStatus: ResourceStatus.Idle,
183+
previousStatus: 'idle',
191184
stream: undefined,
192185
};
193186
} else {
@@ -234,18 +227,15 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
234227
const current = untracked(this.value);
235228
const state = untracked(this.state);
236229

237-
if (
238-
state.status === ResourceStatus.Local &&
239-
(this.equal ? this.equal(current, value) : current === value)
240-
) {
230+
if (state.status === 'local' && (this.equal ? this.equal(current, value) : current === value)) {
241231
return;
242232
}
243233

244234
// Enter Local state with the user-defined value.
245235
this.state.set({
246236
extRequest: state.extRequest,
247-
status: ResourceStatus.Local,
248-
previousStatus: ResourceStatus.Local,
237+
status: 'local',
238+
previousStatus: 'local',
249239
stream: signal({value}),
250240
});
251241

@@ -257,7 +247,7 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
257247
override reload(): boolean {
258248
// We don't want to restart in-progress loads.
259249
const {status} = untracked(this.state);
260-
if (status === ResourceStatus.Idle || status === ResourceStatus.Loading) {
250+
if (status === 'idle' || status === 'loading') {
261251
return false;
262252
}
263253

@@ -274,8 +264,8 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
274264
// Destroyed resources enter Idle state.
275265
this.state.set({
276266
extRequest: {request: undefined, reload: 0},
277-
status: ResourceStatus.Idle,
278-
previousStatus: ResourceStatus.Idle,
267+
status: 'idle',
268+
previousStatus: 'idle',
279269
stream: undefined,
280270
});
281271
}
@@ -290,7 +280,7 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
290280
if (extRequest.request === undefined) {
291281
// Nothing to load (and we should already be in a non-loading state).
292282
return;
293-
} else if (currentStatus !== ResourceStatus.Loading) {
283+
} else if (currentStatus !== 'loading') {
294284
// We're not in a loading or reloading state, so this loading request is stale.
295285
return;
296286
}
@@ -334,8 +324,8 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
334324

335325
this.state.set({
336326
extRequest,
337-
status: ResourceStatus.Resolved,
338-
previousStatus: ResourceStatus.Resolved,
327+
status: 'resolved',
328+
previousStatus: 'resolved',
339329
stream,
340330
});
341331
} catch (err) {
@@ -345,8 +335,8 @@ export class ResourceImpl<T, R> extends BaseWritableResource<T> implements Resou
345335

346336
this.state.set({
347337
extRequest,
348-
status: ResourceStatus.Resolved,
349-
previousStatus: ResourceStatus.Error,
338+
status: 'resolved',
339+
previousStatus: 'error',
350340
stream: signal({error: err}),
351341
});
352342
} finally {
@@ -398,10 +388,10 @@ function isStreamingResourceOptions<T, R>(
398388
*/
399389
function projectStatusOfState(state: ResourceState<unknown>): ResourceStatus {
400390
switch (state.status) {
401-
case ResourceStatus.Loading:
402-
return state.extRequest.reload === 0 ? ResourceStatus.Loading : ResourceStatus.Reloading;
403-
case ResourceStatus.Resolved:
404-
return isResolved(untracked(state.stream!)) ? ResourceStatus.Resolved : ResourceStatus.Error;
391+
case 'loading':
392+
return state.extRequest.reload === 0 ? 'loading' : 'reloading';
393+
case 'resolved':
394+
return isResolved(untracked(state.stream!)) ? 'resolved' : 'error';
405395
default:
406396
return state.status;
407397
}

0 commit comments

Comments
 (0)