jsdoc-duck
TypeScript icon, indicating that this package has built-in type declarations

0.0.5 • Public • Published

jsdoc-duck

jsdoc-duck is a minimalist library that helps organize mid-complex state handling with type-guarded dispatch-capable actions. It leverages useReducer and jsDoc/Javascript to bring type safety and structure to your application's state management. It is based on react-state-factory. The big difference is for simplicity reason don't included useStateReducer counterpart.

this library is also useful for react/typescript application in same way as react-state-factory.

Installation

npm add jsdoc-duck

TLDR

Just define the actions and state then useDuck give back your typed state and quack with list of actions.

jsDoc/JS example

/**
 * @typedef {{ type: "FOO", payload: string[] }
 * | { type: "FUU", payload: number }
 * } ActionsMap
 */
 
/** @type {import('/jsdoc-duck').Labels<ActionsMap>} */ 
const labels = {
  FOO: "FOO",
  FUU: "FUU",
}

/** @typedef {{foo: string[], fuu: number}} FooState */

/** @type {import('jsdoc-duck').Reducer<ActionsMap, FooState>} */
export const fooReducer = (state, { type, payload }) => {
  switch (type) {
    case labels.FOO: return {...state, foo: [...foo, payload]}
    case labels.FUU: return {...state, fuu: payload}
    default: return state;
  }
}

/** @type FooState */
export const fooSetup = {
  foo: ['this is a real minimal foo application', 'are create tokens'],
  fuu: 42
}

export const FooAndFuuComponent = () => {
  const [state, quack] = useDuck(fooReducer, fooSetup, labels);

  const addToken = () => {
    const rnd = Math.random()
    const token = rnd.toString(36).toUpperCase().slice(-7);
    quack.FOO(token);
    quack.FUU(rnd);
  };

  return (
    <pre onClick={addToken}>{JSON.stringify(state, null, 2)}</pre>
  )

Use Case - React Poker Game

This example are under development, and there are just paste the relevant code parts, I would like create a mid-complex application which is a bit complex than casual counter application, where this small library ( less than 100 LOC ) can show the usability of typed useReducer

First of all I create a AM - ActionsMap which is holding group actions with united typedefs

/**
 * @typedef {{ type: "SUMMON", payload: Player[] }
 * | { type: "DECK", payload: [string, string][] }
 * | { type: "NEW_GAME", payload: Player }
 * | { type: "BLINDS", payload: number | string }
 * | { type: "DEALING", payload:  null }
 * | { type: "PRE_FLOP", payload: string }
 * | { type: "FLOP", payload: string }
 * | { type: "TURN", payload: number }
 * | { type: "RIVER", payload: string }
 * | { type: "SHOWDOWN", payload: string }
 * | { type: "CALL", payload: string }
 * | { type: "RAISE", payload: string }
 * | { type: "FOLD", payload: string }
 * | { type: "CHECK", payload: string }
 * | { type: "NEXT_HAND", payload: string }
 * | { type: "ESCAPE", payload: string }
 * | { type: "CHAMPION_ARE", payload: string }
 * | { type: "CALC_RANK", payload: null }
 * } ActionsMap
 */

This is a autogenerated actionsMap aka Labels

/** @type {import('/jsdoc-duck').Labels<ActionsMap>} */ 
const actionsMap = {
  DECK: "DECK",
  SUMMON: "SUMMON",
  NEW_GAME: "NEW_GAME",
  BLINDS: "BLINDS",
  DEALING: "DEALING",
  PRE_FLOP: "PRE_FLOP",
  FLOP: "FLOP",
  TURN: "TURN",
  RIVER: "RIVER",
  SHOWDOWN: "SHOWDOWN",
  CALL: "CALL",
  RAISE: "RAISE",
  FOLD: "FOLD",
  CHECK: "CHECK",
  NEXT_HAND: "NEXT_HAND",
  ESCAPE: "ESCAPE",
  CHAMPION_ARE: "CHAMPION_ARE",
  CALC_RANK: "CALC_RANK"
};

State of game is a simple jsDoc @typedef

/**
 * @typedef {{
 *  players: Player[],
 *  phase: string,
 *  dealer: Player,
 *  deck: [string, string][],
 *  rate: Rate[],
 *  button: string,
 * }} TexasHolden
*/

Reducer cointains the core logic of game

/** @type {import('jsdoc-duck').Reducer<ActionsMap, TexasHolden>} */
export const pokerReducer = (state, { type, payload }) => {
  switch (type) {
    case actionsMap.DECK: return {...state, deck: payload };
    case actionsMap.SUMMON: return {...state, players: payload };
    case actionsMap.NEW_GAME: return {...state, dealer: payload };
    case actionsMap.FLOP: return {...state, phase: FLOP, foo: payload };
    case actionsMap.CALC_RANK: return {...state, rank: rankCalc(state.players, state.dealer)}
    case actionsMap.DEALING: {
      const {deck} = state;
      return {
        ...state,
        phase: actionsMap.DEALING,
        players: state.players.map(player => ({...player, hand: [...player.hand, deck.shift()] })),
        deck
      }
    }
    default: return state;
  }
}

Finally the Poker component with useDuck a dispatchable actions list.

export const Poker = () => {
  // poker, and quack of course in array destruction, so you can give any name which is fit for your component.
  const [poker, quack] = useDuck(pokerReducer, pokerSetup, actionsMap);

  useEffect(() => {
    const deck = aRandomDeck();
    quack.DECK(deck);
    quack.SUMMON(
      "Andy|Boris|Medar|Oriana".split("|").map(name => ({ name, hand: [], coin: 1000 }))
    );
    quack.BLINDS(0);
    quack.NEW_GAME({ name: '- dealer -', hand: [], coin: 0 });
    quack.DEALING();
    quack.DEALING();
    quack.CALC_RANK();
  }, []);

  return (
    <pre>{JSON.stringify(poker, null, 2)}</pre>
  )

Package Sidebar

Install

npm i jsdoc-duck

Weekly Downloads

3

Version

0.0.5

License

MIT

Unpacked Size

19.3 kB

Total Files

16

Last publish

Collaborators

  • pengeszikra