Catch invalid state transitions at compile time, not runtime.
Traditional state machine libraries validate transitions at runtime:
// Using typical library
machine.transition('red', 'yellow'); // ✅ Compiles fine
// 💥 Runtime error: "Invalid transition red -> yellow"This means:
- Bugs aren't caught until runtime
- No IDE autocomplete for valid transitions
- Refactoring is error-prone
- Testing burden is high
TSM uses TypeScript's type system to enforce state machine correctness at compile time:
// Using TSM
const config = defineConfig({
red: ['green'] as const,
green: ['yellow'] as const,
yellow: ['red'] as const,
});
const machine = createMachine('traffic', config)
.setInitial('red')
.build();
await machine.transition('green'); // ✅ Compiles - valid transition
await machine.transition('yellow'); // ❌ TypeScript error - invalid transitionInvalid transitions are TypeScript compilation errors. They never make it to production.
- Invalid transitions are caught by TypeScript
- IDE autocomplete for valid states
- Refactoring is safe - compiler catches breaking changes
- Still validates at runtime for dynamic data
- Clear error messages
- Type-safe throughout
const canProcess = createGuard<Context, Event>(
(context) => context.balance > 0
);
machine.on('pending', 'processing', { guard: canProcess });const logTransition = createAction<Context, Event>(
(context) => console.log('Transitioning...')
);
const updateBalance = createAction<Context, Event>(
(context) => ({ balance: context.balance - 10 })
);
machine.on('processing', 'completed', {
actions: [logTransition, updateBalance]
});interface OrderContext {
orderId: string;
total: number;
attempts: number;
}
const machine = createMachineWithContext(
'order',
config,
{ orderId: '123', total: 99.99, attempts: 0 }
);
machine.getContext(); // Fully typed
machine.updateContext({ attempts: 1 }); // Type-safe updatesmachine.getHistory(); // ['pending', 'processing', 'completed']machine.onTransition((result) => {
console.log(`Transitioned from ${result.from} to ${result.to}`);
});npm install tsmimport { createMachine, defineConfig } from 'tsm';
// Define your states and valid transitions
const config = defineConfig({
idle: ['loading'] as const,
loading: ['success', 'error'] as const,
success: ['idle'] as const,
error: ['idle'] as const,
});
// Create machine
const machine = createMachine('data-fetcher', config)
.setInitial('idle')
.build();
// Use it
await machine.transition('loading');
await machine.transition('success');
console.log(machine.getValue()); // 'success'import {
createMachineWithContext,
defineConfig,
createGuard,
createAction
} from 'tsm';
const config = defineConfig({
locked: ['unlocked'] as const,
unlocked: ['locked'] as const,
});
interface DoorContext {
code: string;
correctCode: string;
attempts: number;
}
const isCorrectCode = createGuard<DoorContext, any>(
(context) => context.code === context.correctCode
);
const incrementAttempts = createAction<DoorContext, any>(
(context) => ({ attempts: context.attempts + 1 })
);
const machine = createMachineWithContext(
'door',
config,
{ code: '', correctCode: '1234', attempts: 0 }
)
.setInitial('locked')
.build();
machine.on('locked', 'unlocked', {
guard: isCorrectCode,
actions: [incrementAttempts]
});
// Set code
machine.updateContext({ code: '1234' });
// Try to unlock
const result = await machine.transition('unlocked');
console.log(result.success); // true if code was correctconst requestConfig = defineConfig({
idle: ['loading'] as const,
loading: ['success', 'error'] as const,
success: ['idle'] as const,
error: ['idle', 'loading'] as const, // can retry
});const authConfig = defineConfig({
loggedOut: ['loggingIn'] as const,
loggingIn: ['loggedIn', 'loginFailed'] as const,
loggedIn: ['loggingOut'] as const,
loggingOut: ['loggedOut'] as const,
loginFailed: ['loggedOut', 'loggingIn'] as const,
});const orderConfig = defineConfig({
pending: ['processing', 'cancelled'] as const,
processing: ['shipped', 'failed'] as const,
shipped: ['delivered'] as const,
delivered: [] as const,
cancelled: [] as const,
failed: ['pending'] as const, // retry
});const characterConfig = defineConfig({
idle: ['walking', 'attacking'] as const,
walking: ['idle', 'running', 'attacking'] as const,
running: ['walking', 'idle'] as const,
attacking: ['idle'] as const,
});Helper for defining state configuration with type inference.
Create a state machine builder.
Create a state machine with initial context.
Transition to a new state. Returns result indicating success/failure.
Get current state.
Get current context.
Update context without changing state.
Get all valid transitions from current state.
Get complete transition history.
Reset to initial state.
Register transition with optional guard and actions.
Register callback for all transitions. Returns unsubscribe function.
Create a type-safe guard function.
Create a type-safe action function.
Combine multiple actions into one.
Combine guards with AND logic.
Combine guards with OR logic.
Negate a guard.
TSM requires TypeScript 4.1+ for template literal types.
Recommended tsconfig.json:
{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"module": "commonjs"
}
}- XState: Runtime validation, complex API, heavyweight
- TSM: Compile-time validation, simple API, lightweight
- robot3: Functional but basic type safety
- TSM: Full compile-time guarantees on transitions
- State.js: JavaScript-first, minimal typing
- TSM: TypeScript-first, maximum type safety
Use TSM when:
- You want compile-time guarantees
- State transitions are known at build time
- You value type safety and IDE support
- You need guards, actions, and context
Don't use TSM when:
- State transitions are completely dynamic
- You need visualization tools (use XState)
- You need hierarchical/parallel states
- You need interpreter/SCXML compliance
TSM has zero runtime overhead for type checking (it's all compile-time).
Runtime performance:
- State transitions: O(1)
- Guard evaluation: O(number of guards)
- Action execution: O(number of actions)
Memory: ~1KB per machine instance (context size dependent)
Enables compile-time validation of transitions without code generation.
Keeps implementation simple and compile-time overhead low. For complex hierarchies, use XState.
Supports real-world use cases (API calls, database operations) without blocking.
Prevents accidental mutations and makes debugging easier.
TSM is part of a larger ecosystem of research projects focused on formal verification and autonomous discovery:
Verifiable Distributed State Machine
- Deterministic Simulation Testing (DST)
- Real-time Formal Verification via Shadow Models
- Post-Quantum Cryptography (Kyber/Dilithium)
Autonomous Mathematical Discovery System
- Systematic exploration of 10^42+ theorem spaces
- Formal verification via Lean 4 & Z3
- Neural pattern learning for guided search
// ... (rest of the content)