statelyai / xstate-tools

Public monorepo for XState tooling
183 stars 36 forks source link

Typegen fails to handle Invoke Meta. #266

Open SimeonC opened 1 year ago

SimeonC commented 1 year ago

Here's the TS Playground for an interactive version.

When we use typegen and the service is a invoke object like { type: 'Service Name', ...other options } then the typegen is getting a random string as the service name insetad of ServiceName (I assume it's getting the object memory reference?).

const machine = createMachine(
  {
    preserveActionOrder: true,
    predictableActionArguments: true,
    tsTypes: {} as import('./test.typegen').Typegen0,
    schema: {
      services: {} as {
        'prompt service': {
          data: any;
        };
      }
    },
    states: {
      One: {
        invoke: {
          src: { type: 'prompt service', option: 1 }
        }
      }
    }
  },
  {
    services: {
      'prompt service': (c, e, meta) => () => {
        if (meta.option >= 1) return Promise.resolve();
        return Promise.reject();
      }
    }
  }
);
// This file was automatically generated. Edits will be overwritten

export interface Typegen0 {
  '@@xstate/typegen': true;
  internalEvents: {
    'xstate.init': { type: 'xstate.init' };
  };
  invokeSrcNameMap: {};
  missingImplementations: {
    actions: never;
    delays: never;
    guards: never;
    services: '96heo3';
  };
  eventsCausingActions: {};
  eventsCausingDelays: {};
  eventsCausingGuards: {};
  eventsCausingServices: {
    '96heo3': never;
  };
  matchesStates: 'One';
  tags: never;
}
// This file was automatically generated. Edits will be overwritten

export interface Typegen0 {
  '@@xstate/typegen': true;
  internalEvents: {
    'xstate.init': { type: 'xstate.init' };
  };
  invokeSrcNameMap: {};
  missingImplementations: {
    actions: never;
    delays: never;
    guards: never;
    services: '96heo3';
  };
  eventsCausingActions: {};
  eventsCausingDelays: {};
  eventsCausingGuards: {};
  eventsCausingServices: {
    '96heo3': never;
  };
  matchesStates: 'One';
  tags: never;
}
SimeonC commented 1 year ago

It'd be really nice if we could get typegen to infer the meta type as well.

Andarist commented 1 year ago

Improvements around this are planned for v5 where we revamp our type definitions as a whole. The goal is to provide as maximum type-safety and inference as possible (sometimes aided by typegen).

SimeonC commented 1 year ago

Looking forward to v5!! This issue is not blocking me as I worked around it with a factory approach and multiple service names (I only had 2 versions in my real code).

services: {
  service1: buildService({ option: 1 }),
  service2: buildService({ option: 2 })
}