XState 类型的操作与事件类型冲突

问题描述 投票:0回答:1

我正在将 XState(5.18.2) 与 TS 一起使用。有些事件类型需要额外的参数,有些则不需要。操作使用事件类型,但似乎不区分哪个操作使用哪些事件。

这里简单重现:

import { setup } from 'xstate'

const exampleMachine = setup({
  types: {
    events: {} as {
      | { type: 'eventWithNoParams' }
      | { type: 'eventWithParams', meta: string }
    }
  },
  actions: {
    doSomething({context, event}, params) {
      event.meta // typeError: Property 'meta' does not exist on type { type: 'eventWithNoParams' } | { type: 'eventWithParams', meta: string }
      params // is type unknown
    }
  }
}).createMachine({
  id: 'example',
  initial: 'start',
  states: {
    start: {
      on: {
        'eventWithNoParams': 'nextState'
      }
    },
    nextState: {
      on: {
        'eventWithParams': 'nextState'
        actions: 'doSomething'
      }
    },
    finalState: {
      type: 'final'
    }
  }
})

const actor = createActor(exampleMachine)
actor.start()
actor.send({type: 'eventWithNoParams'}) // state -> nextState
actor.send({type: 'eventWithParams', meta: 'someData' }) // state -> finalState

代码工作正常,并且操作运行正常,但我在操作定义中遇到错误并且类型安全性为零。我不知道如何确保某些操作仅使用某些事件类型。我在文档中找不到任何示例,其中包含带有额外参数的多个事件以及多个操作的键入示例。

相关链接:

这里提出了类似的问题:XState:属性“操作”的类型不兼容但在 v4 中,它具有完全不同的类型系统和语法。

typescript state-machine xstate
1个回答
0
投票

经过更多阅读和不和谐的一些帮助后,我已经弄清楚了。正确的语法是:

import { setup } from 'xstate'

const exampleMachine = setup({
  types: {
    events: {} as {
      | { type: 'eventWithNoParams' }
      | { type: 'eventWithParams', meta: string }
    }
  },
  actions: {
    doSomething({context, event}, params: { meta: string }) {
      params.meta // simply retype param
    }
  }
}).createMachine({
  id: 'example',
  initial: 'start',
  states: {
    start: {
      on: {
        'eventWithNoParams': 'nextState'
      }
    },
    nextState: {
      on: {
        'eventWithParams': 'nextState'
        actions: {
          type: 'doSomething'
          params: ({ event }) => ({ meta: event.meta }) // pass param here from event. You'll get type inference in event here from the types up top and type inference from the action param typing.
        }
      }
    },
    finalState: {
      type: 'final'
    }
  }
})

const actor = createActor(exampleMachine)
actor.start()
actor.send({type: 'eventWithNoParams'}) // state -> nextState
actor.send({type: 'eventWithParams', meta: 'someData' }) // state -> finalState

有点令人困惑的是,我必须输入两次,但我认为这是有道理的,因为任何

event
都可能触发任何
action
。对于更大的有效负载,可以将类型提取为类型或接口,以获得更好的可重用性。

...
interface Payload { meta: string }
...
types: {
    events: {} as {
      | { type: 'eventWithNoParams' }
      | ({ type: 'eventWithParams' } & Payload)
...
    doSomething({context, event}, params: Payload)
...
© www.soinside.com 2019 - 2024. All rights reserved.