Challenges 5 exercises

Building a Dynamic Reducer

We are going back to the Builder Pattern in this exercise.

Here we have a State interface:

interface State { username: string; password: string; }

The DynamicReducer class can add handlers, and for now contains several unknown types:

export class DynamicRed

Loading exercise


0:01 Builder pattern time. Ooh boy! We have a class here called DynamicReducer, which has a bunch of handlers on it. What it does is, basically, you can call this. You can instantiate it by passing in a generic, which is a State. Let's say the State is username and password.

0:21 We can dynamically add handlers to this. We can say, "addHandler LOG_IN." LOG_IN is a function which takes in a state and an action, which is like username and password here. We're manually defining this. This manual definition, there's a reason we're manually defining this.

0:39 Then what we do is we return username and password here, basically based on the action that's passed in. Then we can add another handler. We say, "addHandler LOG_OUT." It returns username and password.

0:51 Now what we should be able to do is this reducer. A reducer is a function that takes in some state and an action and then returns a new version of that state. We should be able to call reduce with this. It's a pure function that we get back some state. The state should equal username foo and password bar.

1:14 All of the runtime stuff is working here. The test should be passing. There's some more stuff here. It should return the new state after LOG_OUT. We're not expecting the state to be the exact state. We're not doing anything crazy there. We're just expecting it to have a type of State here. Currently, state is just any at the moment.

1:33 Next, we have reducer.reduce. Should error if you pass it an incorrect action. Type NOT_ALLOWED wasn't specified on our LOG_IN or LOG_OUT thing there. It should error there. It should also error if you pass it an incorrect payload. It should have LOG_IN here, but we're not passing it the username and password.

1:56 The information that you pass to addHandler, which is going to be this action type, so username and password here...Sorry. My highlighting thing is just not working at all. There we go. This thing here should be inferred. It should then capture down at the bottom here.

2:15 We've got a little bit of scaffolding here already. We've got our DynamicReducer, but it's not a generic here. Every time we add the handler, we're going to be calling the builder again and basically saying, "We're returning a new instance with this handler added to it."

2:33 You're going to have to remember all the stuff that we learned, like in the end of the classes section, to figure this stuff out. We have a little helper type here. This is PayloadsToDiscriminatedUnion. This should give you a little clue about what is needed here.

2:52 What we've got here is PayloadsToDiscriminatedUnion. If we call it and we call it with an object where the keys are LOG_IN, username, password, string, and LOG_OUT, empty object, what we end up with is basically the type that we are expecting inside the reducer type.

3:12 This is a union where this one is basically type LOG_IN and username, password. This one is type LOG_OUT. It takes these and puts them on there.

3:22 This is a tough problem. I feel a bit cruel giving this to you, but I reckon you can handle it based on all the stuff that you've learned so far. We're into the really hardcore stuff now. I'm pretty sure I've given you everything that you need.

3:38 Obviously, this is going to be generic. You're probably going to need two generics here because we actually pass a type argument to the DynamicReducer at the start. I think addHandler is going to be generic too. I feel bad just pushing you out on your own, but I'm going to do it anyway. Good luck.