Skip to content

Other Decorators

Besides @ChangeState, AFSM provides three decorators for different state-constraint scenarios.

@Includes — include-state guard

Only allow the method to be called when in one of the specified states.

import { Includes } from 'afsm'
class Player extends FSM {
@Includes('playing')
pause() {
// only callable in the playing state
// otherwise throws FSMError
}
}

Signature:

function Includes(...states: string[]): MethodDecorator

Multiple states: @Includes('playing', 'buffering').

@Excludes — exclude-state guard

Disallow calling the method in the specified states.

import { Excludes } from 'afsm'
class Player extends FSM {
@Excludes('disabled')
play() {
// callable in any state except disabled
}
}

Signature:

function Excludes(...states: string[]): MethodDecorator

@ActionState — action state

Temporarily switch to a state during async execution, then return to the original state after.

import { ActionState } from 'afsm'
class Doc extends FSM {
@ActionState('saving')
async save() {
await persist()
// during execution the state is 'saving'; after, it returns to the original
}
}

Signature:

function ActionState(name?: string): MethodDecorator

If name is omitted, the method name is used as the state name.

vs @ChangeState

@ChangeState@ActionState
Before executionvalidates fromno validation, switches directly
After executionenters new stable state toreturns to original state
IntermediateMiddleState (${action}ing)enters name directly
Appears in stateDiagram

Combining decorators

Decorators can stack, applied bottom-up:

class Service extends FSM {
@Includes('idle') // outer: validate state first
@ChangeState('idle', 'done') // inner: then transition
async fetch() {}
}

Usually you’ll use them individually.

Next steps