@ngrx/codegen Proposal

Problem

Developers continue to feel frustrated with the amount of boilerplate they have to write to take full advantage of the NgRx architecture in a strongly typed way. One of the largest sources of boilerplate is Actions. When writing Actions developers have to write the following code if they want to develop strongly typed reducers and effects:

Action Interface
interface LoginAction extends Action {
  type: AuthActionType.LOGIN;
  
  payload: {
    username: string;
    password: string;
  }
}

Action Type Enum
enum AuthActionType {
  LOGIN = '[Auth] Login',
}

Action Interface Union Type
type AuthAction = LoginAction | LogoutAction;

Action Interface Lookup Type
type AuthActionLookup = {
  '[Auth] Login': LoginAction;
  '[Auth] Logout': LogoutAction;
}

Note that we don’t actually ask developers to write this lookup type. However, by generating this type for them we can write a more strongly typed version of the Actions service in @ngrx/effects that can infer the shape of an action when providing an action type to the ofType() operator:

class Actions<T> extends Observable<T> {
  ofType<U extends keyof T>(type: U): Observable<T[U]>;
}

Action Creator Function
function createLoginAction(payload: LoginAction["payload"]): LoginAction {
  return {
    type: '[Auth] Login',
    payload,
  };
}

Note that we currently suggest developers write their actions as classes. This lets them write both the creator function and the interface in one motion, but it leads to confusion when we also suggest they use plain JavaScript objects.

Proposal

Write a codegen tool that can produce the majority of the Action boilerplate. Developers write action interfaces and the tool generates the action type enum, action union type, action lookup type, and action factory functions. 

For example, given a file whose contents look like this:
// auth.actions.ts
import { Action } from '@ngrx/store';