TS-FSM is a strongly typed finite state machine for TypeScript that is using async operations. Library uses generics to take the user states and events. Zero dependencies!
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
git clone https://github.com/eram/typescript-fsm.git
cd typescript-fsm
npm install
npm test
npm install typescript-fsm
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.
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.open, 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);
});
Check out the test code - a class that implements a state machine with method binding, method params and more transitions. 100% coverage here!
Comments and suggestions are welcome.