platform icon indicating copy to clipboard operation
platform copied to clipboard

feat(signals): enhance `withComputed` to automatically add `computed`…

Open rainerhahnekamp opened this issue 5 months ago • 2 comments

Example:

const CounterStore = signalStore(
  withState({ count: 0 }),
  withComputed(({ count }) => ({
    doubleCount: () => count() * 2,
  })),
);
  • Updated withComputed to automatically wrap functions in computed signals.
  • Added tests to verify automatic computation and mixing user-defined computeds.
  • Improved documentation to clarify the factory function's return type.

PR Checklist

Please check if your PR fulfills the following requirements:

  • [x] The commit message follows our guidelines: https://github.com/ngrx/platform/blob/main/CONTRIBUTING.md#commit
  • [x] Tests for the changes have been added (for bug fixes / features)
  • [x] Documentation has been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the current behavior?

Closes #4782

Does this PR introduce a breaking change?

[ ] Yes
[x] No

rainerhahnekamp avatar Jun 07 '25 23:06 rainerhahnekamp

Deploy Preview for ngrx-io failed.

Built without sensitive environment variables

Name Link
Latest commit 370a4744d3033d24cbf5430706114af15e6a7085
Latest deploy log https://app.netlify.com/projects/ngrx-io/deploys/685daeefe41b6000082c3c3e

netlify[bot] avatar Jun 07 '25 23:06 netlify[bot]

Deploy Preview for ngrx-site-v19 ready!

Name Link
Latest commit 370a4744d3033d24cbf5430706114af15e6a7085
Latest deploy log https://app.netlify.com/projects/ngrx-site-v19/deploys/685daeef0dcd410008237be2
Deploy Preview https://deploy-preview-4822--ngrx-site-v19.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

netlify[bot] avatar Jun 07 '25 23:06 netlify[bot]

@markostanimirovic, @timdeschryver.

I've applied the suggested changes with the following additions:

  • ComputedResult calls its type now also ComputedRecord instead ComputedInput.
  • @markostanimirovic, you were suggesting [P in keyof ComputedDictionary]: ComputedDictionary[P] extends Signal<any>; I used [P in keyof ComputedDictionary]: ComputedDictionary[P] extends Signal<unknown>. Is there a reason why any should be preferred over unkown.
  • Type tests have been added to verify that we stick to the Signal type when that one is provided.

rainerhahnekamp avatar Jun 22 '25 09:06 rainerhahnekamp

As discussed, the latest commit enables access to methods within withComputed. This is a necessary step toward supporting a potential withResource feature in the 20.x release line.

When a resource is in an error state, accessing its value will throw. Therefore, users must first verify the presence of a value using the hasValue method.

In the meantime, I am going to prepare the updated docs (in a separate PR).

Since this is a significant change, I've also asked @timdeschryver for a re-review.

const Store = signalStore(
  withResource(() =>
    // spreads members of the resource to the store, including hasValue as method
    resource({
      loader: () => Promise.resolve({ firstName: 'John', lastName: 'Doe' }),
    })
  ),
  withComputed((store) => ({
    safeUser: () =>
      store.user.hasValue()
        ? store.user.value()
        : { firstName: '', lastName: '' },
  }))
);

rainerhahnekamp avatar Jun 23 '25 21:06 rainerhahnekamp

I'd very much like to have the ability to provide a function with a parameter that returns a signal in order to create an equivalent of a factory selector in ngrx store world. I know this can be achieved in the withMethod block but wouldn't it make sense to be able to do that from withComputed when it just all comes down to dealing with signals and not just observables etc?

Just asking because of this comment which would I assume make that hard:

Updated withComputed to automatically wrap functions in computed signals

But maybe the recommendation is to just use withMethod for that?

maxime1992 avatar Jun 26 '25 16:06 maxime1992

@maxime1992

I'd very much like to have the ability to provide a function with a parameter that returns a signal in order to create an equivalent of a factory selector in ngrx store world.

Yes, factory functions for computed are actually methods. So they should go in withMethods. The computed itself is of course also a function in technical terms, but I hope you see the difference in a function creating a computed vs. a function which is wrapped by a computed

rainerhahnekamp avatar Jun 26 '25 19:06 rainerhahnekamp