From efe38c47a7f73a8979b8e55679b3971dc9561dc6 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 18 Sep 2018 17:34:00 -0400 Subject: [PATCH] fix(ngrx): add store typing This adds the `<%= className%>PartialState` used to type the store from the `DataPersistence` methods. This adds the `XXX_FEATURE_KEY` to the `xxx.reducer.ts` file too. close #748 --- .../files/__directory__/__fileName__.effects.ts__tmpl__ | 6 +++--- .../files/__directory__/__fileName__.facade.ts__tmpl__ | 4 ++-- .../files/__directory__/__fileName__.reducer.ts__tmpl__ | 6 ++++++ packages/schematics/src/collection/ngrx/ngrx.spec.ts | 8 ++++---- .../src/collection/ngrx/rules/add-imports-to-module.ts | 4 ++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.effects.ts__tmpl__ b/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.effects.ts__tmpl__ index 1c01b0739e071..02297a5585e04 100644 --- a/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.effects.ts__tmpl__ +++ b/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.effects.ts__tmpl__ @@ -2,13 +2,13 @@ import { Injectable } from '@angular/core'; import { Effect, Actions } from '@ngrx/effects'; import { DataPersistence } from '@nrwl/nx'; -import { <%= className %>State } from './<%= fileName %>.reducer'; +import { <%= className %>PartialState } from './<%= fileName %>.reducer'; import { Load<%= className %>, <%= className %>Loaded, <%= className %>LoadError, <%= className %>ActionTypes } from './<%= fileName %>.actions'; @Injectable() export class <%= className %>Effects { @Effect() load<%= className %>$ = this.dataPersistence.fetch(<%= className %>ActionTypes.Load<%= className %>, { - run: (action: Load<%= className %>, state: <%= className %>State) => { + run: (action: Load<%= className %>, state: <%= className %>PartialState) => { // Your custom REST 'load' logic goes here. For now just return an empty list... return new <%= className %>Loaded([]); }, @@ -21,5 +21,5 @@ export class <%= className %>Effects { constructor( private actions$: Actions, - private dataPersistence: DataPersistence<<%= className %>State>) { } + private dataPersistence: DataPersistence<<%= className %>PartialState>) { } } diff --git a/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.facade.ts__tmpl__ b/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.facade.ts__tmpl__ index 103cba9452083..b8a87461a40ab 100644 --- a/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.facade.ts__tmpl__ +++ b/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.facade.ts__tmpl__ @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { select, Store } from '@ngrx/store'; -import { <%= className %>State } from './<%= fileName %>.reducer'; +import { <%= className %>PartialState } from './<%= fileName %>.reducer'; import { <%= propertyName %>Query } from './<%= fileName %>.selectors'; import { Load<%= className %> } from './<%= fileName %>.actions'; @@ -13,7 +13,7 @@ export class <%= className %>Facade { all<%= className %>$ = this.store.pipe(select(<%= propertyName %>Query.getAll<%= className %>)); selected<%= className %>$ = this.store.pipe(select(<%= propertyName %>Query.getSelected<%= className %>)); - constructor( private store: Store<{<%= propertyName %>: <%= className %>State}> ) { } + constructor(private store: Store<<%= className %>PartialState>) { } loadAll() { this.store.dispatch(new Load<%= className %>()); diff --git a/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.reducer.ts__tmpl__ b/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.reducer.ts__tmpl__ index 66ca050c46ccd..a3207d1faacf3 100644 --- a/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.reducer.ts__tmpl__ +++ b/packages/schematics/src/collection/ngrx/files/__directory__/__fileName__.reducer.ts__tmpl__ @@ -1,5 +1,7 @@ import { <%= className %>Action, <%= className %>ActionTypes } from './<%= fileName %>.actions'; +export const <%= className.toUpperCase() %>_FEATURE_KEY = '<%= propertyName %>'; + /** * Interface for the '<%= className %>' data used in * - <%= className %>State, and @@ -19,6 +21,10 @@ export interface <%= className %>State { error ?: any; // last none error (if any) }; +export interface <%= className %>PartialState { + readonly [<%= className.toUpperCase() %>_FEATURE_KEY]: <%= className %>State; +} + export const initialState: <%= className %>State = { list : [ ], loaded : false diff --git a/packages/schematics/src/collection/ngrx/ngrx.spec.ts b/packages/schematics/src/collection/ngrx/ngrx.spec.ts index 546b5a30a2670..2f000fc04d8db 100644 --- a/packages/schematics/src/collection/ngrx/ngrx.spec.ts +++ b/packages/schematics/src/collection/ngrx/ngrx.spec.ts @@ -166,7 +166,7 @@ describe('ngrx', () => { const appModule = getFileContent(tree, '/apps/myapp/src/app/app.module.ts'); expect(appModule).toContain('StoreModule.forFeature'); expect(appModule).toContain('EffectsModule.forFeature'); - expect(appModule).toContain("'state', stateReducer"); + expect(appModule).toContain('STATE_FEATURE_KEY, stateReducer'); expect(appModule).toContain('{ initialState: stateInitialState }'); expect(appModule).not.toContain( '!environment.production ? [storeFreeze] : []' @@ -357,7 +357,7 @@ describe('ngrx', () => { const content = getFileContent(tree, `${statePath}/users.facade.ts`); [ - `import { UsersState } from './users.reducer'`, + `import { UsersPartialState } from './users.reducer'`, `import { usersQuery } from './users.selectors'`, `export class UsersFacade` ].forEach(text => { @@ -397,11 +397,11 @@ describe('ngrx', () => { `import { DataPersistence } from \'@nrwl/nx\'`, `import { LoadUsers, UsersLoaded, UsersLoadError, UsersActionTypes } from \'./users.actions\'`, `loadUsers$`, - `run: (action: LoadUsers, state: UsersState)`, + `run: (action: LoadUsers, state: UsersPartialState)`, `return new UsersLoaded([])`, `return new UsersLoadError(error)`, 'private actions$: Actions', - 'private dataPersistence: DataPersistence)' + 'private dataPersistence: DataPersistence)' ].forEach(text => { expect(content).toContain(text); }); diff --git a/packages/schematics/src/collection/ngrx/rules/add-imports-to-module.ts b/packages/schematics/src/collection/ngrx/rules/add-imports-to-module.ts index f0d728f1f06b1..3f7a7a5393b43 100644 --- a/packages/schematics/src/collection/ngrx/rules/add-imports-to-module.ts +++ b/packages/schematics/src/collection/ngrx/rules/add-imports-to-module.ts @@ -38,7 +38,7 @@ export function addImportsToModule(context: RequestContext): Rule { const reducerName = `${toPropertyName(context.featureName)}Reducer`; const effectsName = `${toClassName(context.featureName)}Effects`; const facadeName = `${toClassName(context.featureName)}Facade`; - const reducerImports = `initialState as ${featureName}InitialState, ${reducerName}`; + const reducerImports = `${featureName.toUpperCase()}_FEATURE_KEY, initialState as ${featureName}InitialState, ${reducerName}`; const storeReducers = `{ ${featureName}: ${reducerName} }`; const storeInitState = `initialState : { ${featureName} : ${featureName}InitialState }`; @@ -55,7 +55,7 @@ export function addImportsToModule(context: RequestContext): Rule { const storeForEmptyRoot = `StoreModule.forRoot({},{ ${storeMetaReducers} })`; const effectsForRoot = `EffectsModule.forRoot([${effectsName}])`; const effectsForEmptyRoot = `EffectsModule.forRoot([])`; - const storeForFeature = `StoreModule.forFeature('${featureName}', ${reducerName}, { initialState: ${featureName}InitialState })`; + const storeForFeature = `StoreModule.forFeature(${featureName.toUpperCase()}_FEATURE_KEY, ${reducerName}, { initialState: ${featureName}InitialState })`; const effectsForFeature = `EffectsModule.forFeature([${effectsName}])`; const devTools = `!environment.production ? StoreDevtoolsModule.instrument() : []`; const storeRouterModule = 'StoreRouterConnectingModule';