-
-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Strengthen finite state machine types #148
Labels
Comments
Okay, new version, state/events are typed upfront. This is much simpler. import { FiniteStateMachine, type FSMLifecycle } from "runed"
export type AnyState = string
export type AnyEvent = string
export type AnyEventMap = { [K in string]: unknown[] }
export type StateHandler<
State extends AnyState,
Event extends AnyEvent,
EventMap extends AnyEventMap
> = {
[E in Event]?: State
} & {
[E in keyof EventMap]?: (...args: EventMap[E]) => State | void
} & {
[K in FSMLifecycle]?: <E extends null | Event | keyof EventMap>(
meta: E extends null ?
{
from: State | null
to: State
event: null
}
: E extends Event ?
{
from: State | null
to: State
event: E
}
: E extends keyof EventMap ?
{
from: State | null
to: State
event: E
args: EventMap[E]
}
: never
) => void
}
type Transition<State extends AnyState, Event extends AnyEvent, EventMap extends AnyEventMap> = {
[S in State]: StateHandler<State, Event, EventMap>
} & {
"*"?: StateHandler<State, Event, EventMap>
}
export declare class TypedFiniteStateMachine<
State extends AnyState,
Event extends AnyEvent,
EventMap extends AnyEventMap
> {
/** Triggers a new event and returns the new state. */
send<E extends Event | keyof EventMap>(
event: E,
...args: E extends keyof EventMap ? EventMap[E] : never[]
): State | void
/** Debounces the triggering of an event. */
debounce<E extends Event | keyof EventMap>(
wait: number | undefined,
event: E,
...args: E extends keyof EventMap ? EventMap[E] : never[]
): Promise<State>
/** The current state. */
get current(): State
}
export function createFiniteStateMachine<
State extends AnyState,
Event extends AnyEvent,
EventMap extends AnyEventMap = {}
>(
initial: State,
states: Transition<State, Event, EventMap>
): TypedFiniteStateMachine<State, Event, EventMap> {
return new FiniteStateMachine(initial, states)
}
// example
export const machine = createFiniteStateMachine<
"on" | "off",
"turnOn",
{ turnOff: [message: string] }
>("off", {
on: {
turnOff(message) {
console.log({ message })
return "off"
}
},
off: {
turnOn: "on"
},
"*": {
_enter(meta) {
switch (meta.event) {
case "turnOff":
// correctly typed
const [message] = meta.args
console.log({ message })
break
case "turnOn":
// this is an error
const [c] = meta.args
break
}
}
}
})
// correctly typed
machine.send("turnOff", "Hello")
// this is an error
machine.send("turnOn", "Hello") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Describe the feature in detail (code, mocks, or screenshots encouraged)
e.g. calling
send
on a machine should have typed arguments.What type of pull request would this be?
New Feature
Provide relevant links or additional information.
Here's a start.
Some caveats:
unknown[]
The text was updated successfully, but these errors were encountered: