DEV Community

Cover image for Typescript challenge
Peter Vivo
Peter Vivo

Posted on • Updated on

Typescript challenge

I've developed a noteworthy React node module, and I'd like to share the evolutionary journey it has undergone, specifically highlighting the transition from version 0.0.8 to 0.0.9.

react-state-factory

This utility module comprises two vital hooks and a function. Consequently, it supports two distinct development strategies:

useReducer Strategy

This is the traditional approach. If you're not looking to use generator functions for managing asynchronous business logic and simply aim to consolidate multiple useState hooks into one (akin to Redux), this is for you. Furthermore, managing these actions is streamlined with user-defined types.

// useReducer replacement hook
const [state, put] = useStateFactory(reducer, init, labels);
Enter fullscreen mode Exit fullscreen mode

useSagaReducer Strategy

If you prefer to decouple, possibly asynchronous, business logic from your components, then sagas can come to the rescue. This will drastically reduce the reliance on useEffect, leading to tidier code.

// useSagaReducer replacement hook
const [state, put] = useSagaFactory(reducer, init, labels, saga);

// typedPutActionMapFactory
const put = typedPutActionMapFactory(labels);
Enter fullscreen mode Exit fullscreen mode

Challenge

In version 0.0.8, this definition was expressed as:

const put = typedPutActionMapFactory<Labels<ActionsMap>, ActionsMap>(labels);
Enter fullscreen mode Exit fullscreen mode

However, I aimed to eliminate any TypeScript notation. Thus, I refined the code from this:

export function typedPutActionMapFactory<
  EM extends Record<string, string>, 
  AM
>(keys: EM): TypedGeneratorMap<EM, AM> {
  return Object.keys(keys).reduce((acc, type) => ({
    ...acc,
    [type]: function* putGenerator(payload: unknown) {
      yield put({ type, payload });
    }
  }), {} as TypedGeneratorMap<EM, AM>);
}
Enter fullscreen mode Exit fullscreen mode

to (AM moved out from Generic part to Labels):

export function typedPutActionMapFactory<
  AM extends ActionType<any>
>(
  labels: Labels<AM>
): TypedGeneratorMap<AM, Labels<AM>> {
  return Object.keys(labels).reduce((acc, type) => ({
    ...acc,
    [type]: function * putGenerator(payload: any) {
      yield put({ type, payload });
    }
  }), {} as TypedGeneratorMap<AM, Labels<AM>>);
}
Enter fullscreen mode Exit fullscreen mode

This alteration greatly simplifies the process.

react-state-factory hint working on VSCode

Demo Video

I created this video using loom. Loom is an excellent tool for screen recording. With AI assistance, it provides transcription—a boon for non-native English speakers like myself. I've also made videos in Hungarian, and Loom performs impressively in those instances as well. Feel free to dive deeper by watching the extended introduction. Bonus: Loom video can be played at faster speed, I am advice set to: 1.5 x speed!

Transcript

0:01 Hi everyone, I am Peter and I can show the improvement of my library React state factory. All, all relevant code is, in index.ts file.

0:23 In this node module, I define a few typescripts. And after I implement a for function which will be helped to organize or react state handling.

0:49 By the type-guarded react action in two specific way. One is the standard And the useReducer and the other one is the useSagaReducer which library used the Redux saga.

1:18 So with this Thanks. Two different function. I can hop to any user, userReducer user and useSagaReducer user. I show in my example project, this is the card game, theoretical card game.

1:52 Call that table one to show which the difference between the user reducer and use saga reducer so in the main code did you see the use state factually which is use the use reducer and that why I create to use effect to distribute bot Thank you.

2:26 Around the table to sit down the players and in the other use effect start the game with the focus of the first player automatically play his or her first card and after Sorry.

2:58 Uhh, consents to play this card but change the focus to the next player and start the player, draw card. I can switch the order of this action.

3:18 So State Factory is a small library as you see and give a hint to us to each action payload types so I can scroll down.

3:46 Or different action and you saw the different payload type as you see so that's why I created this. It's non-modal and the use-sagafactory way is different because we don't want to create use-effect Thanks for watching!

4:18 Or everything but we we can handle the same way or state in our component so I connect with this line to the useSagaFactory to this saga means saga which this one and you you see the use state methods are there I can get an output which is the same thing as put on ordinary react But, one, so you

5:09 can yield, put and you also use the same actions. So even when you use a used saga factory, you also used effect, it doesn't matter, you can get the put well and you also used action for effects or just a function, simple function when you, for example, click on card, content, then you use this handle

5:53 play. Action, you see, there is the on click we put this effect, we put this action too. So, and now, I working on change my node module to more consistent way because the previous, Peace.

6:28 ,previous version, I used a little bit confusing type definition, so that's why I already implemented action time and labels which works really good, but at this point I used the record string string which is That's the, doesn't exactly describe, well, the definition, so I am the state to check locally

7:13 this modification. Modification will be works, so I am public this module to look local and there and next step you can watch on the next video.

7:32 Thank you for watching, bye everyone.

Top comments (0)