statelyai / xstate

Actor-based state management & orchestration for complex app logic.
https://stately.ai/docs
MIT License
27.21k stars 1.26k forks source link

Bug: Guard Logical Operator Functions Have Type Limitations #5067

Open devanfarrell opened 2 months ago

devanfarrell commented 2 months ago

XState version

XState version 5

Description

A number of these type tests fail typescript validation

  it('should allow mixed guard patterns with logical guard operators', () => {
    setup({
      types: {} as {
        events: { type: 'TEST' };
      },
      guards: {
        paramGuard: (_, _arg: number) => true,
        plainGuard: () => true
      }
    }).createMachine({
      states: {
        plainAnd: {
          on: {
            TEST: {
              guard: and(['plainGuard', 'plainGuard'])
            }
          }
        },
        plainAndWithObjects: {
          on: {
            TEST: {
              guard: and([{ type: 'plainGuard' }, { type: 'plainGuard' }])
            }
          }
        },
        plainAndWithMixed: {
          on: {
            TEST: {
              guard: and(['plainGuard', { type: 'plainGuard' }])
            }
          }
        },
        // ! Failing
        parameterizedAnd: {
          on: {
            TEST: {
              guard: and([
                { type: 'paramGuard', params: () => 1 },
                { type: 'paramGuard', params: () => 1 }
              ])
            }
          }
        },
        // ! Failing
        plainAndParameterizedAnd: {
          on: {
            TEST: {
              guard: and([
                { type: 'plainGuard' },
                { type: 'paramGuard', params: () => 1 }
              ])
            }
          }
        },
        plainNot: {
          on: {
            TEST: {
              guard: not('plainGuard')
            }
          }
        },
        // ! Failing
        parameterizedNot: {
          on: {
            TEST: {
              guard: not({ type: 'paramGuard', params: () => 1 })
            }
          }
        },
        plainComposedAndNot: {
          on: {
            TEST: {
              guard: and([{ type: 'plainGuard' }, not('plainGuard')])
            }
          }
        },
        // ! Failing
        parameterizedComposedAndNot: {
          on: {
            TEST: {
              guard: and([
                { type: 'paramGuard', params: () => 1 },
                not({ type: 'paramGuard', params: () => 1 })
              ])
            }
          }
        }
      }
    });
  });

Expected result

This state machine to pass type validation based on the fact they seem to be supported in code.

Actual result

parameterizedAnd, plainAndParameterizedAnd, parameterizedNot, and parameterizedComposedAndNot do not pass typescript evaluation

Reproduction

https://codesandbox.io/p/sandbox/vigorous-minsky-rl75h2?file=%2Fmachine.ts%3A6%2C7

Additional context

I included a link but this is much easier to see when added to `/packages/core/