Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 86dc97b

Browse files
authored
Merge branch 'main' into feat-rx-state-fn
2 parents 340d93e + a0d56dd commit 86dc97b

File tree

3 files changed

+80
-20
lines changed

3 files changed

+80
-20
lines changed

apps/docs/docs/template/api/rx-if-directive.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ A nice feature of the `*rxIf` directive is, it provides 2 ways to access the [re
161161
162162
The following context variables are available for each template:
163163

164+
- $implicit: `T` the default variable accessed by `let val`
164165
- error: `boolean` | `Error`
165166
- complete: `boolean`
166167
- suspense: `boolean`
@@ -170,12 +171,14 @@ You can use them like this:
170171
**Context Variables on then template**
171172

172173
```html
173-
<ng-container *rxIf="show$; let s = suspense; let e = error, let c = complete">
174+
<ng-container
175+
*rxIf="customer$; let customer; let s = suspense; let e = error, let c = complete"
176+
>
174177
<loader *ngIf="s"></loader>
175178
<error *ngIf="e"></error>
176179
<complete *ngIf="c"></complete>
177180

178-
<app-item></app-item>
181+
<app-customer [customer]="customer"></app-customer>
179182
</ng-container>
180183
```
181184

libs/state/spec/rx-state.service.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ describe('RxStateService', () => {
129129
});
130130

131131
describe('get', () => {
132+
it('should return readonly state', () => {
133+
service.set({ bol: false });
134+
// @ts-expect-error Cannot assign to 'bol' because it is a read-only property.
135+
service.get().bol = true;
136+
// service.get() returns a reference to the state object so it is mutable.
137+
expect(service.get().bol).toBe(true);
138+
});
139+
132140
it('should return undefined as initial value', () => {
133141
const state = setupState({ initialState: undefined });
134142
const val = state.get();
@@ -155,6 +163,16 @@ describe('RxStateService', () => {
155163
});
156164

157165
describe('select', () => {
166+
it('should have readonly state projection', () => {
167+
const state = setupState({ initialState: initialPrimitiveState });
168+
state.select(['num', 'bol'], (x) => {
169+
// @ts-expect-error Cannot assign to 'num' because it is a read-only property.
170+
x.num = 1;
171+
return x;
172+
});
173+
expect(state.get().num).toBe(initialPrimitiveState.num);
174+
});
175+
158176
it('should return undefined as initial value', () => {
159177
testScheduler.run(({ expectObservable }) => {
160178
const state = setupState({ initialState: undefined });
@@ -273,6 +291,16 @@ describe('RxStateService', () => {
273291
});
274292

275293
describe('set', () => {
294+
it('should have readonly state projection', () => {
295+
service.set({ bol: false });
296+
service.set((s) => {
297+
// @ts-expect-error Cannot assign to 'bol' because it is a read-only property.
298+
s.bol = true;
299+
return { bol: false };
300+
});
301+
expect(service.get().bol).toBe(false);
302+
});
303+
276304
describe('with state partial', () => {
277305
it('should add new slices', () => {
278306
const state = setupState({});
@@ -338,6 +366,16 @@ describe('RxStateService', () => {
338366
});
339367

340368
describe('connect', () => {
369+
it('should have readonly state projection', () => {
370+
service.set({ bol: false });
371+
service.connect(of({ bol: true }), (s) => {
372+
// @ts-expect-error Cannot assign to 'bol' because it is a read-only property.
373+
s.bol = true;
374+
return { bol: false };
375+
});
376+
expect(service.get().bol).toBe(false);
377+
});
378+
341379
it('should work with observables directly', () => {
342380
testScheduler.run(({ expectObservable }) => {
343381
const state = setupState({ initialState: initialPrimitiveState });

libs/state/src/lib/rx-state.service.ts

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,18 @@ import {
2121
} from 'rxjs';
2222
import { catchError, map, tap } from 'rxjs/operators';
2323

24-
export type ProjectStateFn<T> = (oldState: T) => Partial<T>;
25-
export type ProjectValueFn<T, K extends keyof T> = (oldState: T) => T[K];
24+
export type ProjectStateFn<T> = (oldState: Readonly<T>) => Partial<T>;
25+
export type ProjectValueFn<T, K extends keyof T> = (
26+
oldState: Readonly<T>
27+
) => T[K];
2628

27-
export type ProjectStateReducer<T, V> = (oldState: T, value: V) => Partial<T>;
29+
export type ProjectStateReducer<T, V> = (
30+
oldState: Readonly<T>,
31+
value: V
32+
) => Partial<T>;
2833

2934
export type ProjectValueReducer<T, K extends keyof T, V> = (
30-
oldState: T,
35+
oldState: Readonly<T>,
3136
value: V
3237
) => T[K];
3338

@@ -105,9 +110,9 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
105110
* doStuff();
106111
* }
107112
*
108-
* @return T
113+
* @return Readonly<T>
109114
*/
110-
get(): T;
115+
get(): Readonly<T>;
111116

112117
/**
113118
* @description
@@ -123,33 +128,36 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
123128
*
124129
* const foo = state.get('bar', 'foo');
125130
*
126-
* @return T | T[K1] | T[K1][K2]
131+
* @return Readonly<T> | Readonly<T[K1]> | Readonly<T[K1][K2]>
127132
*/
128133

129-
get<K1 extends keyof T>(k1: K1): T[K1];
134+
get<K1 extends keyof T>(k1: K1): Readonly<T[K1]>;
130135
/** @internal **/
131-
get<K1 extends keyof T, K2 extends keyof T[K1]>(k1: K1, k2: K2): T[K1][K2];
136+
get<K1 extends keyof T, K2 extends keyof T[K1]>(
137+
k1: K1,
138+
k2: K2
139+
): Readonly<T[K1][K2]>;
132140
/** @internal **/
133141
get<K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(
134142
k1: K1,
135143
k2: K2,
136144
k3: K3
137-
): T[K1][K2][K3];
145+
): Readonly<T[K1][K2][K3]>;
138146
/** @internal **/
139147
get<
140148
K1 extends keyof T,
141149
K2 extends keyof T[K1],
142150
K3 extends keyof T[K1][K2],
143151
K4 extends keyof T[K1][K2][K3]
144-
>(k1: K1, k2: K2, k3: K3, k4: K4): T[K1][K2][K3][K4];
152+
>(k1: K1, k2: K2, k3: K3, k4: K4): Readonly<T[K1][K2][K3][K4]>;
145153
/** @internal **/
146154
get<
147155
K1 extends keyof T,
148156
K2 extends keyof T[K1],
149157
K3 extends keyof T[K1][K2],
150158
K4 extends keyof T[K1][K2][K3],
151159
K5 extends keyof T[K1][K2][K3][K4]
152-
>(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): T[K1][K2][K3][K4][K5];
160+
>(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): Readonly<T[K1][K2][K3][K4][K5]>;
153161
/** @internal **/
154162
get<
155163
K1 extends keyof T,
@@ -158,7 +166,14 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
158166
K4 extends keyof T[K1][K2][K3],
159167
K5 extends keyof T[K1][K2][K3][K4],
160168
K6 extends keyof T[K1][K2][K3][K4][K5]
161-
>(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5, k6: K6): T[K1][K2][K3][K4][K5][K6];
169+
>(
170+
k1: K1,
171+
k2: K2,
172+
k3: K3,
173+
k4: K4,
174+
k5: K5,
175+
k6: K6
176+
): Readonly<T[K1][K2][K3][K4][K5][K6]>;
162177
/** @internal **/
163178
get<
164179
K1 extends keyof T,
@@ -175,14 +190,15 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
175190
| [K1, K2, K3, K4]
176191
| [K1, K2, K3, K4, K5]
177192
| [K1, K2, K3, K4, K5, K6]
178-
):
193+
): Readonly<
179194
| T
180195
| T[K1]
181196
| T[K1][K2]
182197
| T[K1][K2][K3]
183198
| T[K1][K2][K3][K4]
184199
| T[K1][K2][K3][K4][K5]
185-
| T[K1][K2][K3][K4][K5][K6] {
200+
| T[K1][K2][K3][K4][K5][K6]
201+
> {
186202
const hasStateAnyKeys = Object.keys(this.accumulator.state).length > 0;
187203
if (!!keys && keys.length) {
188204
return safePluck(this.accumulator.state, keys);
@@ -230,7 +246,7 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
230246
* @param {ProjectValueFn<T, K>} projectSlice
231247
* @return void
232248
*/
233-
set<K extends keyof T, O>(key: K, projectSlice: ProjectValueFn<T, K>): void;
249+
set<K extends keyof T>(key: K, projectSlice: ProjectValueFn<T, K>): void;
234250
/**
235251
* @internal
236252
*/
@@ -489,7 +505,7 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
489505
*/
490506
select<K extends keyof T, V>(
491507
keys: K[],
492-
fn: (slice: PickSlice<T, K>) => V,
508+
fn: (slice: Readonly<PickSlice<T, K>>) => V,
493509
keyCompareMap?: KeyCompareMap<Pick<T, K>>
494510
): Observable<V>;
495511
/**
@@ -503,7 +519,10 @@ export class RxState<T extends object> implements OnDestroy, Subscribable<T> {
503519
*
504520
* @return Observable<V>
505521
*/
506-
select<K extends keyof T, V>(k: K, fn: (val: T[K]) => V): Observable<V>;
522+
select<K extends keyof T, V>(
523+
k: K,
524+
fn: (val: Readonly<T[K]>) => V
525+
): Observable<V>;
507526
/**
508527
* @description
509528
* Access a single property of the state by providing keys.

0 commit comments

Comments
 (0)