Skip to content

fix(store): remove SelectorWithProps and MemoizedSelectorWithProps#5080

Open
david-shortman wants to merge 4 commits intongrx:mainfrom
david-shortman:fix/remove-selector-with-props
Open

fix(store): remove SelectorWithProps and MemoizedSelectorWithProps#5080
david-shortman wants to merge 4 commits intongrx:mainfrom
david-shortman:fix/remove-selector-with-props

Conversation

@david-shortman
Copy link
Contributor

@david-shortman david-shortman commented Jan 30, 2026

Remove all deprecated SelectorWithProps and MemoizedSelectorWithProps types
and APIs, deprecated since v12 (#2980). Adds a v21 migration schematic that
removes imports, auto-converts string-key selects, and adds inline TODO comments
at select(selector, props) call sites requiring manual migration. Updates the
migration guide with BEFORE/AFTER examples for factory selectors and a memoized
composition pattern.

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

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

Closes #3035

What is the new behavior?

  • SelectorWithProps and MemoizedSelectorWithProps types are removed from @ngrx/store
  • createSelector overloads accepting selectors with props are removed
  • createSelectorFactory overloads returning MemoizedSelectorWithProps are removed
  • Store.select() and select() operator no longer accept props or string keys
  • defaultStateFn no longer handles the props branch
  • Testing utilities (MockStore, MockSelector) no longer reference MemoizedSelectorWithProps
  • ESLint rule prefix-selectors-with-select no longer checks for removed types
  • Downstream packages updated: router-store service, standalone-app pipe, data test
  • A v21 migration schematic:
    • Removes SelectorWithProps/MemoizedSelectorWithProps imports
    • Auto-converts select('key') string-key calls to select((state: any) => state['key'])
    • Adds inline // TODO comments at select(selector, props) call sites that need manual migration
    • Logs warnings to the console for call sites requiring manual migration
  • The v21 migration guide documents the breaking change with:
    • Factory selector BEFORE/AFTER pattern
    • Memoized factory pattern (using createSelector to memoize the factory)
    • Note explaining that selectors with props did not memoize properly in practice

Does this PR introduce a breaking change?

[x] Yes
[ ] No

SelectorWithProps, MemoizedSelectorWithProps, and all related overloads have been removed. Users should migrate to factory selectors. Note that selectors with props did not memoize properly in practice — defaultMemoize uses strict reference equality (===), so passing inline object literals as props defeated memoization on every change detection cycle.

BEFORE:

const selectCustomer = createSelector(
  selectCustomers,
  (customers, props: { customerId: number }) => customers[props.customerId]
);
this.store.select(selectCustomer, { customerId: 42 });

AFTER (factory selector):

const selectCustomer = (customerId: number) =>
  createSelector(selectCustomers, (customers) => customers[customerId]);
this.store.select(selectCustomer(42));

AFTER (memoized factory — createSelector memoizes the projector, so repeated calls with the same argument return the same inner selector instance):

const selectCustomer = createSelector(
  (customerId: number) => customerId,
  (customerId) =>
    createSelector(selectCustomers, (customers) => customers[customerId])
);

// selectCustomer(42) returns a memoized selector;
// calling selectCustomer(42) again returns the same instance.
this.store.select(selectCustomer(42));

String-key selectors (this.store.select('featureName')) have also been removed in favor of selector functions.

@netlify
Copy link

netlify bot commented Jan 30, 2026

Deploy Preview for ngrx-io ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit cfcf051
🔍 Latest deploy log https://app.netlify.com/projects/ngrx-io/deploys/697cba5ffb7c930008f2e4a0
😎 Deploy Preview https://deploy-preview-5080--ngrx-io.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.

Remove all deprecated selector-with-props APIs that were deprecated
since v12 (issue ngrx#2980). This includes:

- `SelectorWithProps` type from models
- `MemoizedSelectorWithProps` interface from selector
- 16 `createSelector` overloads accepting `SelectorWithProps`
- 2 `createSelectorFactory` overloads returning `MemoizedSelectorWithProps`
- `Store.select()` overloads accepting props and string keys
- Standalone `select()` operator overloads accepting props and string keys
- Related types in mock store/selector testing utilities
- ESLint rule references to removed types
- Documentation section on selectors with props

Adds a v21 migration schematic that removes `SelectorWithProps` and
`MemoizedSelectorWithProps` imports from user code, and updates the v21
migration guide with BEFORE/AFTER examples for converting to factory
selectors.

Closes ngrx#3035

BREAKING CHANGES:

`SelectorWithProps` and `MemoizedSelectorWithProps` types have been
removed. Use factory selectors instead.

BEFORE:

const selectCustomer = createSelector(
  selectCustomers,
  (customers, props: { customerId: number }) => customers[props.customerId]
);
this.store.select(selectCustomer, { customerId: 42 });

AFTER:

const selectCustomer = (customerId: number) =>
  createSelector(selectCustomers, (customers) => customers[customerId]);
this.store.select(selectCustomer(42));

String-key selectors have also been removed.

BEFORE:

this.store.select('featureName');

AFTER:

this.store.select((state) => state.featureName);

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@david-shortman david-shortman force-pushed the fix/remove-selector-with-props branch from 5ac3e64 to c80bbc5 Compare January 30, 2026 05:59
david-shortman and others added 3 commits January 30, 2026 01:16
- Fix router-store build: convert string-key select to selector fn
- Fix standalone-app: convert string-key select to selector fn
- Fix data package test: convert string-key select to selector fn
- Migration: add inline TODO comments at select(selector, props) sites
- Migration guide: add memoization note and composition pattern
- Update API reference docs to reflect removed overloads

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use createSelector to memoize the factory itself, so repeated calls
with the same argument return the same inner selector instance.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a big one that needs to be discussed with the team (because it can break many legacy apps).
If it gets accepted the first release that can include this is v22.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove SelectorWithProps

2 participants