Skip to content

Commit fd8f347

Browse files
feat(store): remove deprecated createFeature method (#3825)
Closes #3814 BREAKING CHANGES: The `createFeature` signature with root state is removed in favor of a signature without root state. An automatic migration is added to remove this signature. BEFORE: ```ts interface AppState { users: State; } export const usersFeature = createFeature<AppState>({ name: 'users', reducer: createReducer(initialState, /* case reducers */), }); ``` AFTER: ```ts export const usersFeature = createFeature({ name: 'users', reducer: createReducer(initialState, /* case reducers */), }); ```
1 parent 351a75e commit fd8f347

File tree

2 files changed

+0
-193
lines changed

2 files changed

+0
-193
lines changed

modules/store/spec/types/feature_creator.spec.ts

Lines changed: 0 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -173,187 +173,6 @@ describe('createFeature()', () => {
173173
});
174174
});
175175

176-
describe('with passed app state type', () => {
177-
it('should create', () => {
178-
const snippet = expectSnippet(`
179-
const enter = createAction('[Books Page] Enter');
180-
const loadBooksSuccess = createAction(
181-
'[Books API] Load Books Success',
182-
props<{ books: Book[] }>()
183-
);
184-
185-
interface Book {
186-
id: number;
187-
title: string;
188-
}
189-
190-
type LoadState = 'init' | 'loading' | 'loaded' | 'error';
191-
192-
interface BooksState {
193-
books: Book[];
194-
loadState: LoadState;
195-
}
196-
197-
interface AppState {
198-
books: BooksState;
199-
}
200-
201-
const initialState: BooksState = {
202-
books: [],
203-
loadState: 'init',
204-
};
205-
206-
const booksFeature = createFeature<AppState>({
207-
name: 'books',
208-
reducer: createReducer(
209-
initialState,
210-
on(enter, (state) => ({ ...state, loadState: 'loading' })),
211-
on(loadBooksSuccess, (state, { books }) => ({
212-
...state,
213-
books,
214-
loadState: 'loaded',
215-
}))
216-
),
217-
});
218-
219-
const {
220-
name,
221-
reducer,
222-
selectBooksState,
223-
selectBooks,
224-
selectLoadState,
225-
} = booksFeature;
226-
227-
let booksFeatureKeys: keyof typeof booksFeature;
228-
`);
229-
230-
snippet.toInfer('name', '"books"');
231-
snippet.toInfer('reducer', 'ActionReducer<BooksState, Action>');
232-
snippet.toInfer(
233-
'selectBooksState',
234-
'MemoizedSelector<AppState, BooksState, (featureState: BooksState) => BooksState>'
235-
);
236-
snippet.toInfer(
237-
'selectBooks',
238-
'MemoizedSelector<AppState, Book[], (featureState: BooksState) => Book[]>'
239-
);
240-
snippet.toInfer(
241-
'selectLoadState',
242-
'MemoizedSelector<AppState, LoadState, (featureState: BooksState) => LoadState>'
243-
);
244-
snippet.toInfer(
245-
'booksFeatureKeys',
246-
'"selectBooksState" | "selectBooks" | "selectLoadState" | keyof FeatureConfig<"books", BooksState>'
247-
);
248-
});
249-
250-
it('should create a feature when reducer is created outside', () => {
251-
const snippet = expectSnippet(`
252-
interface State {
253-
bar: string;
254-
}
255-
const initialState: State = { bar: 'ngrx' };
256-
257-
const fooReducer = createReducer(initialState);
258-
const fooFeature = createFeature<{ foo: State }>({
259-
name: 'foo',
260-
reducer: fooReducer,
261-
});
262-
263-
const {
264-
name,
265-
reducer,
266-
selectFooState,
267-
selectBar,
268-
} = fooFeature;
269-
`);
270-
271-
snippet.toInfer('name', '"foo"');
272-
snippet.toInfer('reducer', 'ActionReducer<State, Action>');
273-
snippet.toInfer(
274-
'selectFooState',
275-
'MemoizedSelector<{ foo: State; }, State, (featureState: State) => State>'
276-
);
277-
snippet.toInfer(
278-
'selectBar',
279-
'MemoizedSelector<{ foo: State; }, string, (featureState: State) => string>'
280-
);
281-
});
282-
283-
it('should fail when name is not key of app state', () => {
284-
expectSnippet(`
285-
interface AppState {
286-
counter1: number;
287-
counter2: number;
288-
}
289-
290-
const counterFeature = createFeature<AppState>({
291-
name: 'counter3',
292-
reducer: createReducer(0),
293-
});
294-
`).toFail(
295-
/Type '"counter3"' is not assignable to type '"counter1" | "counter2"'/
296-
);
297-
});
298-
299-
it('should allow use with StoreModule.forFeature', () => {
300-
expectSnippet(`
301-
const counterFeature = createFeature<{ counter: number }>({
302-
name: 'counter',
303-
reducer: createReducer(0),
304-
});
305-
306-
StoreModule.forFeature(counterFeature);
307-
`).toSucceed();
308-
});
309-
310-
it('should allow use with untyped store.select', () => {
311-
expectSnippet(`
312-
const { selectCounterState, selectCount } = createFeature<{ counter: { count: number } }>({
313-
name: 'counter',
314-
reducer: createReducer({ count: 0 }),
315-
});
316-
317-
let store!: Store;
318-
const counterState$ = store.select(selectCounterState);
319-
const count$ = store.select(selectCount);
320-
`).toFail(
321-
/Type 'object' is not assignable to type '{ counter: { count: number; }; }'/
322-
);
323-
});
324-
325-
it('should allow use with typed store.select', () => {
326-
const snippet = expectSnippet(`
327-
const { selectCounterState } = createFeature<{ counter: number }>({
328-
name: 'counter',
329-
reducer: createReducer(0),
330-
});
331-
332-
let store!: Store<{ counter: number }>;
333-
const counterState$ = store.select(selectCounterState);
334-
`);
335-
336-
snippet.toInfer('counterState$', 'Observable<number>');
337-
});
338-
339-
it('should fail when feature state contains optional properties', () => {
340-
expectSnippet(`
341-
interface CounterState {
342-
count?: number;
343-
}
344-
345-
interface AppState {
346-
counter: CounterState;
347-
}
348-
349-
const counterFeature = createFeature<AppState>({
350-
name: 'counter',
351-
reducer: createReducer({} as CounterState),
352-
});
353-
`).toFail(/optional properties are not allowed in the feature state/);
354-
});
355-
});
356-
357176
describe('nested selectors', () => {
358177
it('should not create with feature state as a primitive value', () => {
359178
expectSnippet(`

modules/store/src/feature_creator.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,6 @@ export function createFeature<FeatureName extends string, FeatureState>(
9292
featureConfig: FeatureConfig<FeatureName, FeatureState> &
9393
NotAllowedFeatureStateCheck<FeatureState>
9494
): Feature<Record<string, any>, FeatureName, FeatureState>;
95-
/**
96-
* @deprecated Use the `createFeature` signature without root state instead.
97-
* For more info see: https://github.com/ngrx/platform/issues/3737
98-
*/
99-
export function createFeature<
100-
AppState extends Record<string, any>,
101-
FeatureName extends keyof AppState & string = keyof AppState & string,
102-
FeatureState extends AppState[FeatureName] = AppState[FeatureName]
103-
>(
104-
featureConfig: FeatureConfig<FeatureName, FeatureState> &
105-
NotAllowedFeatureStateCheck<FeatureState>
106-
): Feature<AppState, FeatureName, FeatureState>;
10795
/**
10896
* @description
10997
* A function that accepts a feature name and a feature reducer, and creates

0 commit comments

Comments
 (0)