Skip to content

Commit 8f1b79e

Browse files
committed
feat(devtools): add branded Action type and asAction helper
2 parents 83f6b12 + 6dbb7a8 commit 8f1b79e

7 files changed

Lines changed: 113 additions & 10 deletions

File tree

docs/docs/community.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: Community
3+
---
4+
5+
We are thankful for the community surrounding the Toolkit.
6+
7+
Here are some links with respect to two types of community involvement:
8+
9+
1. Addons to the code
10+
1. Content about the Toolkit
11+
1. Discord
12+
13+
## Addons
14+
15+
### ngrx-toolkit-openapi-gen
16+
17+
[Murat Sari](https://github.com/wolfmanfx) created an OpenAPI generator that creates:
18+
19+
✅ an NgRx Signal Store
20+
21+
✅ with Resources
22+
23+
✅ and Mutations
24+
25+
✅ based on a Zod schema
26+
27+
[Check it out here](https://www.npmjs.com/package/ngrx-toolkit-openapi-gen)
28+
29+
## Content
30+
31+
- Zoaib Khan
32+
- [Blog post: "Use withResource to seamlessly combine Resources with Ngrx Signals Store!"](https://zoaibkhan.com/blog/use-withresource-to-seamlessly-combine-resources-with-ngrx/)
33+
- [YouTube short: "Local Storage Sync with Ngrx Signal Store"](https://www.youtube.com/shorts/wbRxCCUrGvk)
34+
- Angular Space livestreams
35+
- [Rainer's appearance](https://youtu.be/UUhZm52tigQ?t=2930), taking general Toolkit questions from Angular Space host Armen Vardanyan
36+
- [Michael Small's appearance](https://youtu.be/X59d8GJnNhE?t=603), speaking about Mutations when they were being RFC'd, and `withResource`.
37+
- [Jason Warner (@xocomil) speaks about `withResource/withMutations` on a livestream](https://www.youtube.com/watch?v=kitcmXNj5K0&t=6344s)
38+
- Michael Small is an active chat member on Jason's streams, so Jason has talked about the Toolkit a lot on stream, and probably will in the future if he keeps humoring Michael.
39+
40+
## Discord
41+
42+
Community contributions are sometimes shared on our Discord. [Link to join the NgRx Toolkit Discord](https://discord.gg/xnkSWDmpXZ). Feel free to share your Toolkit related content there, as well as any general discussion that may not fit cleanly under a GitHub issue or discussion post.

docs/docs/mutations.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,16 @@ const save = await store.save({...}); if (inc.status === 'error')
218218
### Signal values
219219

220220
```ts
221-
// Signals
221+
// value: Signal<Result | undefined>;
222+
// status: Signal<MutationStatus>;
223+
// isPending: Signal<boolean>;
224+
// isSuccess: Signal<boolean>;
225+
// error: Signal<unknown>;
222226

223-
// via store
224-
store.increment.value; // also status/error/isPending/status/hasValue;
227+
// via store in `withMutation`
228+
store.incrementValue;
225229

226-
// via member variable
230+
// via member variable if defined outside of `withMutation`
227231
mutationName.value; // ^^^
228232
```
229233

@@ -288,9 +292,8 @@ export type Mutation<Parameter, Result> = {
288292
hasValue(): this is Mutation<Exclude<Parameter, undefined>, Result>; // type narrows `.value()`
289293
};
290294

291-
// Accessed from store or variable
292-
storeName.mutationName.value; // or other signals
293-
mutationName.value; // ^^^
295+
storeName.mutationNameValue; // `withMutations`
296+
mutationName.value; // no `withMutations`
294297
```
295298

296299
#### Callbacks: `onSuccess` and `onError` (optional)

docs/docusaurus.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ const config: Config = {
9494
position: 'left',
9595
label: 'Team',
9696
},
97+
{
98+
type: 'docSidebar',
99+
sidebarId: 'communitySidebar',
100+
position: 'left',
101+
label: 'Community',
102+
},
97103
{
98104
href: 'https://github.com/angular-architects/ngrx-toolkit',
99105
label: 'GitHub',

docs/sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const sidebars: SidebarsConfig = {
3838
},
3939
],
4040
teamSidebar: ['team'],
41+
communitySidebar: ['community'],
4142

4243
// But you can create a sidebar manually
4344
/*

libs/ngrx-toolkit/src/lib/devtools/with-tracked-reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from '@ngrx/signals/events';
1616
import { tap } from 'rxjs/operators';
1717
import { GLITCH_TRACKING_FEATURE } from './features/with-glitch-tracking';
18-
import { updateState, asAction } from './update-state';
18+
import { asAction, updateState } from './update-state';
1919
import { DEVTOOL_FEATURE_NAMES } from './with-devtools';
2020

2121
export function withTrackedReducer<State extends object>(

libs/ngrx-toolkit/src/lib/with-mutations.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing';
22
import { patchState, signalStore, withState } from '@ngrx/signals';
33
import { delay, Observable, of, Subject, switchMap, throwError } from 'rxjs';
44
import { concatOp, exhaustOp, mergeOp, switchOp } from './flattening-operator';
5+
import { Mutation, MutationResult } from './mutation/mutation';
56
import { rxMutation } from './mutation/rx-mutation';
7+
import { Assert, AssertNot, IsEqual } from './test-utils/types';
68
import { withMutations } from './with-mutations';
79

810
type Param =
@@ -534,4 +536,53 @@ describe('withMutations with rxMutation', () => {
534536
error: 'Test-Error',
535537
});
536538
});
539+
540+
it('does not expose mutation properties directly, only the method', async () => {
541+
// Test case for https://github.com/angular-architects/ngrx-toolkit/issues/286
542+
const testSetup = createTestSetup(switchOp);
543+
const store = testSetup.store;
544+
545+
expect(typeof store.increment).toEqual('function');
546+
// @ts-expect-error Should not expose properties, only the method
547+
expect(store.increment.isPending).toBeUndefined();
548+
});
549+
550+
it('types mutation method as plain callable Promise signature and returns nothing else from a mutation', () => {
551+
// Test case for https://github.com/angular-architects/ngrx-toolkit/issues/286
552+
const testSetup = createTestSetup();
553+
const store = testSetup.store;
554+
555+
// Only the method is exposed
556+
type _T1 = Assert<
557+
IsEqual<
558+
typeof store.increment,
559+
(params: Param) => Promise<MutationResult<number>>
560+
>
561+
>;
562+
563+
// Other mutation properties not present
564+
type _T2 = AssertNot<
565+
IsEqual<typeof store.increment, Mutation<Param, number>>
566+
>;
567+
568+
// _T2 in other words:
569+
570+
// CAN...
571+
// Still can call mutation function
572+
store.increment(0);
573+
574+
// CANNOT...
575+
// @ts-expect-error should not expose properties, only method call
576+
const status = store.increment.status;
577+
// @ts-expect-error should not expose properties, only method call
578+
const value = store.increment.value;
579+
// @ts-expect-error should not expose properties, only method call
580+
const isPending = store.increment.isPending;
581+
// @ts-expect-error should not expose properties, only method call
582+
const isSuccess = store.increment.isSuccess;
583+
// @ts-expect-error should not expose properties, only method call
584+
const error = store.increment.error;
585+
// @ts-expect-error should not expose properties, only method call
586+
const hasValue = store.increment.hasValue;
587+
});
537588
});

libs/ngrx-toolkit/src/lib/with-mutations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
withMethods,
1111
WritableStateSource,
1212
} from '@ngrx/signals';
13-
import { Mutation, MutationStatus } from './mutation/mutation';
13+
import { Mutation, MutationResult, MutationStatus } from './mutation/mutation';
1414

1515
// NamedMutationMethods below will infer the actual parameter and return types
1616
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -33,7 +33,7 @@ type NamedMutationMethods<T extends MutationsDictionary> = {
3333
infer P,
3434
infer R
3535
>
36-
? Mutation<P, R>
36+
? (params: P) => Promise<MutationResult<R>>
3737
: never;
3838
};
3939

0 commit comments

Comments
 (0)