# 15. Strongly type our store

## 1. Add types to our reducer

By community convention most people put the types for each slice of state with the reducer, which makes sense as this is where you update the slice of state. Here will will make an interface for shape of the slice of state and use it to type a constant to make our initial state. It is a good idea to always make initial state so we can be confident what we will get when we start subscribing to the store before any actions that might update the state are dispatched.

* Add an interface and initial state to our spinner reducer.

{% code title="src/app/state/spinner.reducer.ts" %}

```typescript
export interface State {
  isOn: boolean;
}

export const initialState: State = {
  isOn: false
};

export function reducer(state = initialState, action): State {
  switch (action.type) {
    case 'startSpinner': {
      return {
        isOn: true
      };
    }

    case 'stopSpinner': {
      return {
        isOn: false
      };
    }

    default:
      return state;
  }
}

```

{% endcode %}

## 2. Add a global state interface

This is a difficult task as most applications lazily load the majority of their state, meaning we can only specify the state that is always loaded when the app loads. We can then extend our feature state objects to have these "global" state reducers.&#x20;

* Create a state.ts file in our state folder.
* Add a global interface to describe all the global state that will be initialised up front in our application on load.

{% code title="src/app/state/state.ts" %}

```typescript
import * as fromSpinner from './spinner/spinner.reducer';

export interface State {
  spinner: fromSpinner.State;
}

```

{% endcode %}

## 3.  Use global interface in EventComponent

Now we can inject the Store into our components with a type. This is useful to say what state reducers we should be able to interact with from this component but in reality the store is a global object and these types do not stop us getting the whole store.

* Update the store to use the new State interface.

{% code title="src/app/event/container/event/event.component.ts" %}

```typescript
----------- ABBREVIATED CODE SNIPPPET ----------
  
  constructor(
    private store: Store<State>,
    private eventService: EventService
  ) {}


----------- ABBREVIATED CODE SNIPPPET ----------
```

{% endcode %}

## 4.  Create action creators

Action creators are a big part of making an Angular application that uses NgRx more robust. It helps get type inference and code hints in our app and stops users dispatching actions with mistakes or the wrong actions with maybe the wrong payloads.

The `SpinnerActionTypes` enum is useful for having a strongly typed list of the actions we can dispatch. It is also handy to have detail in them so when we see them in our dev tools we can also see the place and time they are dispatched from, making debugging easier when we are less familiar with the code written by other or even ourselves.

* Create a spinner.actions.ts file in our *state/spinner* folder.
* Make action creators to strongly type our actions.

{% code title="src/app/state/spinner/spinner.actions.ts" %}

```typescript
import { Action } from '@ngrx/store';

export enum SpinnerActionTypes {
  StartSpinner = '[Spinner Page] Start Spinner',
  StopSpinner = '[Spinner Page] Stop Spinner'
}

export class StartSpinner implements Action {
  readonly type = SpinnerActionTypes.StartSpinner;
}

export class StopSpinner implements Action {
  readonly type = SpinnerActionTypes.StopSpinner;
}

export type SpinnerActions = StopSpinner | StartSpinner;

```

{% endcode %}

## 5.  Use action creators in our components

* Use action creators in EventComponent and remove our un typed actions we are dispatching.

{% code title="src/app/event/event.component.ts" %}

```typescript
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Store, select } from '@ngrx/store';

import { Attendee } from '../../../models';
import { EventService } from '../../services/event.service';
import { State } from '../../../state/state';
import { StartSpinner, StopSpinner } from '../../../state/spinner/spinner.actions';

@Component({
  selector: 'app-event',
  templateUrl: './event.component.html',
  styleUrls: ['./event.component.scss']
})
export class EventComponent implements OnInit {
  spinner$: Observable<boolean>;
  attendees$: Observable<Attendee[]>;

  constructor(
    private store: Store<State>,
    private eventService: EventService
  ) {}

  ngOnInit() {
    this.getAttendees();
    this.spinner$ = this.store.pipe(select(state => state.spinner.isOn));
  }

  getAttendees() {
    this.attendees$ = this.eventService.getAttendees();
  }

  addAttendee(attendee: Attendee) {
    this.store.dispatch(new StartSpinner());
    this.eventService.addAttendee(attendee).subscribe(() => {
      this.store.dispatch(new StopSpinner());
      this.getAttendees();
    });
  }
}

```

{% endcode %}

## 6. Use ActionTypes and Actions type in reducer

We will break our unit tests by using our `SpinnerActionTypes` which now have a different string and words for the type argument of our actions but we will fix these in the next section.

* Type the action argument passed into our reducer function as `SpinnerActions`.
* Change our case statements to use our new `SpinnerActionTypes`.

{% code title="src/app/state/spinner.reducer.ts" %}

```typescript
import { SpinnerActionTypes, SpinnerActions } from './spinner.actions';

export interface State {
  isOn: boolean;
}

export const initialState: State = {
  isOn: false
};

export function reducer(state = initialState, action: SpinnerActions): State {
  switch (action.type) {
    case SpinnerActionTypes.StartSpinner: {
      return {
        isOn: true
      };
    }

    case SpinnerActionTypes.StopSpinner: {
      return {
        isOn: false
      };
    }

    default:
      return state;
  }
}

```

{% endcode %}

## StackBlitz Link

{% embed url="<https://stackblitz.com/github/duncanhunter/angular-and-ngrx-demo-app/tree/15-strongly-type-ngrx>" %}
Web Link: Link to the demo app running in StackBlitz
{% endembed %}

## Extras and Homework

{% hint style="danger" %}
These extra sections are for doing after the course or if you finish a section early. Please move onto the next section if doing this as a workshop when the instructor advises.

WARNING: Some of these extra sections will make it more difficult to copy and paste the code examples later on in the course.

You might need to apply the code snippet examples a little more carefully amongst any "extras section" code you may add. If you are up for some extra challenges these sections are for you.
{% endhint %}

### Learn more about Action Hygiene from the NgRx team in this ngConf you tube video

{% embed url="<https://www.youtube.com/watch?v=JmnsEvoy-gY>" %}

Steps:

1. Watch the video&#x20;
