How to deal with nullable state properties from NgRx in Angular components using TypeScript?

Viewed 147

I'm using Angular 11, TypeScript and NgRx as state management. My app state contains a currentProject property which is retrieved from a backend. Hence, at initial startup the value is undefined.

export interface AppState { 
   currentProject?: Project; // <--- Note the ? to denote that at application startup there is no currentProject and hence the value can be undefined.
}

In the CurrentProjectComponent context in the app there always is a currentProject value in the state.

// Angular CurrentProjectComponent
....
public currentProject$!: Observable<Project>;

constructor(private store: Store<{ app: AppState >) {
    this.currentProject$ = this.store.select((s) => s.currentProject); 
}
...

But when I write code to select the code from the state, I end up in undesired type casting. I either have to

  • type my currentProject$ field as Project | undefined, which leads to trouble when passing its value further to pipes and other components. I would end up in typing alsmost my whole domain model in Project | undefined which kind of defeats the point.
  • add an as Project cast to the NgRx selector
  • filter out undefined currentProject values by writing: this.store.select((s) => s.currentProject).pipe(filter(p => !!p)); but this does not work either:

TS2322: Type 'Observable<Project | undefined>' is not assignable to type 'Observable < Project >'.

The best solution I could come up with is to filter undefined values and then cast:

constructor(private store: Store<{ app: AppState >) {
    this.currentProject$ = this.store.select((s) => s.currentProject).pipe(filter(p => !!p)) as Observable<Project>; 
}

But is this really needed in order to being able to use TypeScript? This solution does not feel like TypeScript is helping here.

0 Answers
Related