State machine code with no implementation:
const trainingMachine = createMachine<TrainingContext>({
predictableActionArguments: true,
id: 'training',
initial: 'initial',
context: {},
states: {
initial: {
on: {| mapped types syntax and intro | |
| https://www.typescriptlang.org/play?#code/C4TwDgpgBA8gRgKygXigbwFBW1AZge3wC4oBnYAJwEsA7AcwBosc4BDCkmgVwFs4IKGAL4YMoSFACSAEwg1gVUAB4AKgD4U6ZtgDaAaSi0oAawgh8uKCoC6JFfuvDR46AGVWPaKhlyFy+AhqGAD0wTgAegD8omLg0AAKFPg8VKRUuCCqGqiYOFD6hjQmZhZWtlAAFACUKBqJyakQqg5BIrES9SlpuFQQ0pqdqemZAUGhEdEYsgDGADbs0NP4NORQFGDTJIPdvdKiSyvAeFzAXBReaxsAdGwU1SFheU-PUFGiuCdnEFfAABZyFQqADdWLMasgNLkcCDZtooOM3kIqkA | |
| a tweet that prompted the idea for the talk | |
| https://twitter.com/kentcdodds/status/1608187990215655424 | |
| but since this isn't possible with satisfies (it doesn't participate in inference, in an example like that it only provides contextual types) the answer was to use a function with a reverse mapped type |
State machine code with no implementation:
const trainingMachine = createMachine<TrainingContext>({
predictableActionArguments: true,
id: 'training',
initial: 'initial',
context: {},
states: {
initial: {
on: {| export const make = Effect.struct({ | |
| ref: SubscriptionRef.make(0), | |
| }); | |
| export interface Counter extends Effect.Success<typeof make> {} | |
| export const Counter = Tag<Counter>(); | |
| export const CounterLive = Layer.fromEffect(Counter)(make); | |
| export const increment = Effect.serviceWithEffect(Counter, ({ ref }) => | |
| ref.update((count) => count + 1) |
| // WIP, just finding all the boxes and glue, implementation is woefully incomplete | |
| import type { DOMAttributes } from "react"; | |
| import { assign, createMachine, interpret } from "@xstate/fsm"; | |
| import invariant from "tiny-invariant"; | |
| type CustomElement<T> = Partial< | |
| T & DOMAttributes<T> & { children: any; class: string } | |
| >; |
| export class Cache<T extends object, K> { | |
| items = new WeakMap<T, K>() | |
| get<P extends T>(item: P, cb: (item: P) => K) { | |
| if (!this.items.has(item)) { | |
| this.items.set(item, cb(item)) | |
| } | |
| return this.items.get(item)! | |
| } |
| /* eslint-disable no-param-reassign */ | |
| import { | |
| getMembers, types | |
| } from 'mobx-state-tree' | |
| import { | |
| createMachine | |
| } from 'xstate' | |
| import { interpret } from 'xstate/lib/interpreter' | |
| // Pieced together from: |
A zone is an isolated portion of an @xstate/test model. A zone defines the events it uses, the event that causes it to be entered and the states within the zone
The zones entryEvent is added as an event handler to the zones parent initial state. If this is a root zone passed to buildTestModel this is the root state, if it's a sub zone (a state pointing at a zone), that is the initial state of the zone that state is contained in
Each state in a zone must contain a test property that validates that the state has been entered. At least one of the states requires it to be marked as the initial state of the zone with initial: true
An event handler in a zone state can only refer to events defined inside of the zone
| type State = string; | |
| type Message = string; | |
| type StatesList = readonly State[]; | |
| type MessagesConfig = Record<State, Record<Message, State>>; | |
| type OneOf<S extends StatesList> = S[number]; | |
| type Send< | |
| SBConfig extends StateBuilderConfig<StatesList, State, State>, |
Thoughts on standardizing REST with machines