From 73980d5c889e4a3bbd1ec57f926f5ab95b34f670 Mon Sep 17 00:00:00 2001 From: Daniel K Date: Mon, 21 Dec 2020 12:53:14 +0100 Subject: [PATCH] Add Interpreter helper for useService support --- .changeset/hungry-waves-kneel.md | 5 +++ .../examples/trafficLightMachine.machine.ts | 14 ++++++- packages/xstate-compiled/readme.md | 38 ++++++++++++++++++- .../src/templates/index.d.ts.hbs | 2 + 4 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 .changeset/hungry-waves-kneel.md diff --git a/.changeset/hungry-waves-kneel.md b/.changeset/hungry-waves-kneel.md new file mode 100644 index 0000000..5b079cf --- /dev/null +++ b/.changeset/hungry-waves-kneel.md @@ -0,0 +1,5 @@ +--- +'xstate-codegen': patch +--- + +Add Interpreter helper type for useService typing diff --git a/packages/xstate-compiled/examples/trafficLightMachine.machine.ts b/packages/xstate-compiled/examples/trafficLightMachine.machine.ts index d0c9189..99a7ce1 100644 --- a/packages/xstate-compiled/examples/trafficLightMachine.machine.ts +++ b/packages/xstate-compiled/examples/trafficLightMachine.machine.ts @@ -1,5 +1,5 @@ -import { Machine, interpret } from '@xstate/compiled'; -import { useMachine } from '@xstate/compiled/react'; +import { Machine, interpret, LightMachineInterpreter } from '@xstate/compiled'; +import { useMachine, useService } from '@xstate/compiled/react'; type LightEvent = | { type: 'TIMER' } @@ -95,3 +95,13 @@ const interpretTrafficLightMachine = () => { ); return interpreter; }; + +type LightMachineService = LightMachineInterpreter; + +const useTrafficLightService = (service: LightMachineService) => { + const [state, send] = useService(service); + state.matches('green'); + // @ts-expect-error + state.matches('wrong'); + return [state, send]; +}; diff --git a/packages/xstate-compiled/readme.md b/packages/xstate-compiled/readme.md index faa070d..c7d7594 100644 --- a/packages/xstate-compiled/readme.md +++ b/packages/xstate-compiled/readme.md @@ -37,13 +37,47 @@ You must pass three type options to `createMachine/Machine`: For instance: ```ts -import { Machine } from '@xstate/compiled'; +import { Machine, UniqueIdInterpreter } from '@xstate/compiled'; interface Context {} type Event = { type: 'DUMMY_TYPE' }; -const machine = Machine({}); +const machine = Machine({ + states: { + first: {} + second: {} + } +}); + +type UniqueIdService = UniqueIdInterpreter +``` + +### React support + +For use with React you can import `useMachine` from `@xstate/compiled/react` instead for better type support. + +Namely the `state.matches()` will type check against state schema properly. + +```ts +import { useMachine } from '@xstate/compiled/react'; + +const [state, send, service] = useMachine(machine); // machine from previous example +state.matches('first'); // correctly type checked +state.matches('wrong'); // produces error +``` + +The `service` variable is useful to be passed to other components either through props or context. +Notice in the first example how we have declared `UniqueIdService`. You can use that type in such cases. + +```ts +import { useService } from '@xstate/compiled/react'; + +function UniqueComponent({ service }: { service: UniqueIdService }) { + const [state] = useService(service); + state.matches('first'); // correctly type checked + state.matches('wrong'); // produces error +} ``` ## Options diff --git a/packages/xstate-compiled/src/templates/index.d.ts.hbs b/packages/xstate-compiled/src/templates/index.d.ts.hbs index 0f9d3ac..63c033b 100644 --- a/packages/xstate-compiled/src/templates/index.d.ts.hbs +++ b/packages/xstate-compiled/src/templates/index.d.ts.hbs @@ -157,6 +157,8 @@ declare module '@xstate/compiled' { >['_options']> ): this; } + + export type {{capitalize this.id}}Interpreter = InterpreterWithMatches {{/each}} export interface RegisteredMachinesMap {