question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Builder/Factory pattern for better type propagation in TypeScript/Flow

See original GitHub issue

Current handleActions(reducerMap, ?defaultState) signature doesn’t allow the propagation of payload types from actions into reducers, as it is a dictionary type.

A builder or factory pattern like the following would allow for better type propagation

let increment = createAction<void>('INCREMENT');
let decrement = createAction<number>('DECREMENT');

ReducerBuilder()
.addReducer(increment, (state, action) => {})
.addReducer(decrement, (state, action) => {})
.toReducerMap();

The reason being the actions could be typed as Action<void> and Action<number> respectively, and .addReducer can be typed as

function addReducer<TState, TPayload>(action: Action<TPayload>, handler: (state: TState, action: Action<TPayload>)=>{});

This would automated propagate the type into the reducer.

Issue Analytics

  • State:open
  • Created 7 years ago
  • Comments:5

github_iconTop GitHub Comments

1reaction
krawallercommented, May 18, 2017

One year late to the party, but: I’ve used and appreciated @leonyu’s setup for a while now (thank you!!). Partly because of how nice it plays with TypeScript, but I also prefer that pattern over the regular one in handleActions.

Not saying it is justified adding it to the package though, I do understand @alexgorbatchev’s hesitation.

If anyone like me stumbles across this PR in search of some TypeScript guidance, I go over my implementation of @leonyu’s idea here (along with a handleActions comparison).

0reactions
leonyucommented, Apr 28, 2016

I was looking at this package, and it looked promising for my use, but it didn’t satisfy my need of propagating types without needing runtime

I already have an implementation of it in my own code:

// usage
const reducer = new ReducerBuilder<AuthState>()
.add(QUERY_AUTHENTICATION, (state, action) => Object.assign({}, state, action.payload))
.build();

// implementation
class ReducerBuilder<TState> {
    private map : { [action: string]: Reducer<TState, any>; };
    constructor() {
        this.map = {}
    }
    add<TPayload>(action: ActionCreator<TPayload>, reducer: Reducer<TState, TPayload>) {
        this.map[action.type] = reducer;
        return this;
    }
    build(): Reducer<TState, any> {
        const mapClone = Object.assign({}, this.map);
        return (state: TState = {} as any, action: Action<any>) => {
            let handler = mapClone[action.type];
            return handler ? handler(state, action) : state;
        }
    }
}

It is trivial to convert the above to less OOP syntax, which would be a lot less verbose. (I used OOP because it would be more familiar to the others on the team)

function builder() {
   /* impl */
   return {
      add(action, reducer) { /* impl */ }
      done() { /* impl */ }
   }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Understanding design patterns in TypeScript and Node.js
This tutorial runs through several design patterns you can utilize with TypeScript and Node, including singleton and abstract factory.
Read more >
TypeScript 4 Design Patterns and Best Practices - Section 1
TypeScript 4 Design Patterns and Best Practices - Section 1 - Discover effective techniques and design patterns for every programming task.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found