Last active
October 9, 2024 02:40
-
-
Save mmyoji/8c6ddde79ae1598494ee11a22d312e79 to your computer and use it in GitHub Desktop.
State machine in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @example | |
* ```ts | |
* const POST_STATE = { | |
* DRAFT: 0, | |
* PUBLISHED: 1, | |
* // ... | |
* } as const; | |
* type PostState = (typeof POST_STATE)[keyof typeof POST_STATE]; | |
* | |
* const POST_EVENT = { | |
* publish: { | |
* from: POST_STATE.DRAFT, | |
* to: POST_STATE.PUBLISHED, | |
* }, | |
* withdraw: { | |
* from: MY_STATE.PUBLISHED, | |
* to: MY_STATE.DRAFT, | |
* }, | |
* // ... | |
* } as const; | |
* type PostEvent = keyof typeof POST_EVENT; | |
* | |
* const updatePostState = createStateMachine(POST_EVENT); | |
* | |
* { | |
* const next = updatePostState(POST_STATE.DRAFT, "publish"); | |
* //=> 1 | |
* } | |
* | |
* { | |
* const next = updatePostState(POST_STATE.PUBLISHED, "publish"); | |
* //=> Error("Invalid transition: 1 -> 1"); | |
* } | |
* ``` | |
*/ | |
export function createStateMachine<Event extends string, State extends number | string>( | |
event: Record<Event, { from: State; to: State }> | |
): (prev: State, evt: Event) => State { | |
return (prev, evt) => { | |
const e = event[evt]; | |
if (e == null) { | |
throw new Error(`Unknown event: ${evt}`); | |
} | |
if (prev !== e.from) { | |
throw new Error(`Invalid transition: ${prev} -> ${e.to}`); | |
} | |
return e.to; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment