typescript-fsm
TypeScript icon, indicating that this package has built-in type declarations

1.4.5 • Public • Published

TypeScript State Machine (typescript-fsm)

Build Status npm package It's already here!

Finite state machines are useful for modeling complicated flows and keeping track of state. TS-FSM is a strongly typed finite state machine for TypeScript that is using promises for async operations. I'm using this state-machine as a simple replacement for Redux in some ReactJs based apps. Example here

Features

  • TypeScript native (compiles to ES6)
  • Only 1 KB (minified) and zero dependencies!!!
  • Hooks after state change - - async or sync callbacks
  • Promises are used for async transition completion
  • Generics for states and events types
  • Simple tabular state machine definition
  • Use with NodeJS or JS client

Get it

# git clone https://github.com/eram/typescript-fsm.git
# cd typescript-fsm
# npm install
# npm test

Use it

npm install typescript-fsm

Basic Example

I'm modeling a "door" here. One can open the door, close it or break it. Each action is done async: when you open it goes into opening state and then resolved to opened state etc. Once broken, it reaches a final state.

Door state machine

Let's code it in Typescript! Note that the same code can be run in Javascript, just remove the generics.

import { t, StateMachine } from "typescript-fsm";

// these are the states and events for the door
enum States { closing = 0, closed, opening, opened, broken };
enum Events { open = 100, openComplete, close, closeComplete, break };

// lets define the transitions that will govern the state-machine
const transitions = [
  /* fromState        event                 toState         callback */
  t(States.closed,    Events.opened,        States.opening, onOpen),
  t(States.opening,   Events.openComplete,  States.opened,  justLog),
  t(States.opened,    Events.close,         States.closing, onClose),
  t(States.closing,   Events.closeComplete, States.closed,  justLog),
  t(States.closed,    Events.break,         States.broken,  justLog),
  t(States.opened,    Events.break,         States.broken,  justLog),
  t(States.opening,   Events.break,         States.broken,  justLog),
  t(States.closing,   Events.break,         States.broken,  justLog),
];

// initialize the state machine
const door = new StateMachine<States, Events>(
   States.closed,   // initial state
   transitions,     // array of transitions 
);

// transition callbacks - async functions
async function onOpen() {
    console.log("onOpen...");
    return door.dispatch(Events.openComplete);
}

async function onClose() {
    console.log("onClose...");
    return door.dispatch(Events.closeComplete);
}

// synchronous callbacks are also ok
function justLog() { 
    console.log(`${States[door.getState()]}`);
}

// we are ready for action - run a few state-machine steps...
new Promise(async (resolve) => {

    // open the door and wait for it to be opened
    await door.dispatch(Events.open);
    door.getState(); // => States.opened

    // check if the door can be closed
    door.can(Events.close); // => true

    // break the door async
    door.dispatch(Events.break).then(() => {
        // did we get to a finite state?
        door.isFinal(); // => true 
    });

    // door is now broken. It cannot be closed...
    try {
        await door.dispatch(Events.close);
        assert("should not get here!");
    } catch (e) {
        // we're good
    }

    // let the async complete
    setTimeout(resolve, 10);
});

Another example

Check out the test code - a class that implements a state machine with method binding, method params and more transitions. 100% coverage here!

Beautiful :-)

Comments and suggestions are welcome.

Package Sidebar

Install

npm i typescript-fsm

Weekly Downloads

938

Version

1.4.5

License

Apache 2.0

Unpacked Size

24.3 kB

Total Files

12

Last publish

Collaborators

  • ethanram