https://github.com/eram/typescript-fsm
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!
https://github.com/eram/typescript-fsm
fsm generics no-dependencies promise state-machine typescript
Last synced: about 1 year ago
JSON representation
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!
- Host: GitHub
- URL: https://github.com/eram/typescript-fsm
- Owner: eram
- License: mit
- Created: 2017-05-25T15:54:04.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2025-04-10T11:21:58.000Z (about 1 year ago)
- Last Synced: 2025-04-15T03:49:11.272Z (about 1 year ago)
- Topics: fsm, generics, no-dependencies, promise, state-machine, typescript
- Language: TypeScript
- Homepage:
- Size: 275 KB
- Stars: 202
- Watchers: 2
- Forks: 21
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# TypeScript State Machine (typescript-fsm)
[](https://app.travis-ci.com/github/eram/typescript-fsm)
[](https://www.npmjs.com/package/typescript-fsm)

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](https://github.com/eram/tensorflow-stack-ts/blob/master/client/src/components/server-status-card/StatusCardModel.ts)
## 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
```script
git clone https://github.com/eram/typescript-fsm.git
cd typescript-fsm
npm install
npm test
```
## Use it
```script
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.

Let's code it in Typescript! Note that the same code can be run in Javascript, just remove the generics.
```typescript
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.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](https://github.com/eram/typescript-fsm/blob/master/src/__test__/stateMachine.test.ts) - a class that implements a state machine with method binding, method params and more transitions. 100% coverage here!
## Beautiful :-)
Comments and suggestions are [welcome](https://github.com/eram/typescript-fsm/issues/new).