refactor: add successOr, sweep remaining inline unwraps (RD-17)
Eight sites hand-rolled `rd.tag === 'Success' ? rd.value : fallback`. Six take the new `successOr(rd, fallback)`, one takes the existing `successOf`, and one (`big-profile.store.ts`) uses the existing `map`, since it returns a RemoteData rather than an unwrapped value. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Injectable, computed, inject, signal } from '@angular/core';
|
||||
import { RemoteData } from '@shared/application/remote-data';
|
||||
import { RemoteData, successOr } from '@shared/application/remote-data';
|
||||
import { runSubmit } from '@shared/application/submit';
|
||||
import { Result, ok, err } from '@shared/kernel/fp';
|
||||
import { FeatureFlag } from '@shared/domain/feature-flag';
|
||||
@@ -22,10 +22,7 @@ export class FeatureFlagStore {
|
||||
|
||||
readonly flags = this.state.asReadonly();
|
||||
/** The resolved list (empty until loaded) — for the admin toggle UI. */
|
||||
readonly all = computed(() => {
|
||||
const rd = this.state();
|
||||
return rd.tag === 'Success' ? rd.value : [];
|
||||
});
|
||||
readonly all = computed(() => successOr(this.state(), []));
|
||||
|
||||
constructor() {
|
||||
void this.load();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { RemoteData, fromLoadLifecycle, map2, map, successOf } from './remote-data';
|
||||
import { RemoteData, fromLoadLifecycle, map2, map, successOf, successOr } from './remote-data';
|
||||
import { loading, failure, empty, success } from '../testing/remote-data';
|
||||
|
||||
const loadingRd: RemoteData<string, number> = loading();
|
||||
@@ -34,6 +34,18 @@ describe('successOf', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('successOr', () => {
|
||||
it('unwraps a Success value', () => {
|
||||
expect(successOr(ok(2), 0)).toBe(2);
|
||||
});
|
||||
|
||||
it('is the fallback for every other state', () => {
|
||||
expect(successOr(loadingRd, [])).toEqual([]);
|
||||
expect(successOr(failureRd, [])).toEqual([]);
|
||||
expect(successOr(empty(), null)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromLoadLifecycle', () => {
|
||||
it('maps Loading → Loading', () => {
|
||||
expect(fromLoadLifecycle({ tag: 'Loading' })).toEqual(loading());
|
||||
|
||||
@@ -109,3 +109,13 @@ export function andThen<E, A, B>(
|
||||
export function successOf<E, T>(rd: RemoteData<E, T>): T | undefined {
|
||||
return rd.tag === 'Success' ? rd.value : undefined;
|
||||
}
|
||||
|
||||
/** Unwrap a Success value, or a caller-supplied `fallback` for every other state.
|
||||
Reach for this over `successOf` when `undefined` is not a usable value at the
|
||||
call site (e.g. a list the template iterates, which wants `[]`). Reach for
|
||||
`map` instead when the site needs to stay a `RemoteData`, not an unwrapped
|
||||
value. Three type parameters: `fallback` need not be assignable to `T`
|
||||
(an empty array is not a `T[]` at the type level, only at the value level). */
|
||||
export function successOr<E, T, F>(rd: RemoteData<E, T>, fallback: F): T | F {
|
||||
return rd.tag === 'Success' ? rd.value : fallback;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user