From e21e3f959971efbe1add5646a0adef04cf913524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 30 Nov 2023 07:21:04 +0100 Subject: [PATCH] Fixed an issue with contextual parameters in input factories of input-less actors (#4523) * Fixed an issue with contextual parameters in input factories of input-less actors * Changeset --------- Co-authored-by: David Khourshid --- .changeset/khaki-bees-melt.md | 5 +++++ packages/core/src/actors/callback.ts | 14 +++++++++----- packages/core/src/actors/observable.ts | 20 +++++++++++++++----- packages/core/src/actors/promise.ts | 6 +++--- packages/core/src/actors/transition.ts | 7 ++++--- packages/core/src/setup.ts | 3 ++- packages/core/src/types.ts | 11 +++++++++-- packages/core/test/setup.types.test.ts | 22 ++++++++++++++++++++++ 8 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 .changeset/khaki-bees-melt.md diff --git a/.changeset/khaki-bees-melt.md b/.changeset/khaki-bees-melt.md new file mode 100644 index 0000000000..5ddb68acb9 --- /dev/null +++ b/.changeset/khaki-bees-melt.md @@ -0,0 +1,5 @@ +--- +'xstate': patch +--- + +Fixed an issue with contextual parameters in input factories of input-less actors diff --git a/packages/core/src/actors/callback.ts b/packages/core/src/actors/callback.ts index b1196f6796..3955fbe390 100644 --- a/packages/core/src/actors/callback.ts +++ b/packages/core/src/actors/callback.ts @@ -6,7 +6,8 @@ import { ActorSystem, ActorRefFrom, Snapshot, - AnyActorRef + AnyActorRef, + NonReducibleUnknown } from '../types'; import { XSTATE_STOP } from '../constants.ts'; @@ -26,12 +27,12 @@ export type CallbackSnapshot = Snapshot & { export type CallbackActorLogic< TEvent extends EventObject, - TInput = unknown + TInput = NonReducibleUnknown > = ActorLogic, TEvent, TInput, ActorSystem>; export type CallbackActorRef< TEvent extends EventObject, - TInput = unknown + TInput = NonReducibleUnknown > = ActorRefFrom>; export type Receiver = ( @@ -43,7 +44,7 @@ export type Receiver = ( export type InvokeCallback< TEvent extends EventObject = AnyEventObject, TSentEvent extends EventObject = AnyEventObject, - TInput = unknown + TInput = NonReducibleUnknown > = ({ input, system, @@ -132,7 +133,10 @@ export type InvokeCallback< * }); * ``` */ -export function fromCallback( +export function fromCallback< + TEvent extends EventObject, + TInput = NonReducibleUnknown +>( invokeCallback: InvokeCallback ): CallbackActorLogic { const logic: CallbackActorLogic = { diff --git a/packages/core/src/actors/observable.ts b/packages/core/src/actors/observable.ts index 7b11020d9a..148133291f 100644 --- a/packages/core/src/actors/observable.ts +++ b/packages/core/src/actors/observable.ts @@ -6,20 +6,27 @@ import { Subscription, AnyActorSystem, ActorRefFrom, - Snapshot + Snapshot, + NonReducibleUnknown } from '../types'; const XSTATE_OBSERVABLE_NEXT = 'xstate.observable.next'; const XSTATE_OBSERVABLE_ERROR = 'xstate.observable.error'; const XSTATE_OBSERVABLE_COMPLETE = 'xstate.observable.complete'; -export type ObservableSnapshot = Snapshot & { +export type ObservableSnapshot< + TContext, + TInput extends NonReducibleUnknown +> = Snapshot & { context: TContext | undefined; input: TInput | undefined; _subscription: Subscription | undefined; }; -export type ObservableActorLogic = ActorLogic< +export type ObservableActorLogic< + TContext, + TInput extends NonReducibleUnknown +> = ActorLogic< ObservableSnapshot, { type: string; [k: string]: unknown }, TInput, @@ -70,7 +77,7 @@ export type ObservableActorRef = ActorRefFrom< * @see {@link https://rxjs.dev} for documentation on RxJS Observable and observable creators. * @see {@link Subscribable} interface in XState, which is based on and compatible with RxJS Observable. */ -export function fromObservable( +export function fromObservable( observableCreator: ({ input, system @@ -214,7 +221,10 @@ export function fromObservable( * canvasActor.start(); * ``` */ -export function fromEventObservable( +export function fromEventObservable< + T extends EventObject, + TInput extends NonReducibleUnknown +>( lazyObservable: ({ input, system diff --git a/packages/core/src/actors/promise.ts b/packages/core/src/actors/promise.ts index 97ebbf8ebb..cd9da973b6 100644 --- a/packages/core/src/actors/promise.ts +++ b/packages/core/src/actors/promise.ts @@ -1,11 +1,12 @@ +import { XSTATE_STOP } from '../constants'; import { ActorLogic, ActorRefFrom, ActorSystem, AnyActorSystem, + NonReducibleUnknown, Snapshot } from '../types'; -import { XSTATE_STOP } from '../constants'; export type PromiseSnapshot = Snapshot & { input: TInput | undefined; @@ -82,8 +83,7 @@ export type PromiseActorRef = ActorRefFrom< * // } * ``` */ -export function fromPromise( - // TODO: add types +export function fromPromise( promiseCreator: ({ input, system diff --git a/packages/core/src/actors/transition.ts b/packages/core/src/actors/transition.ts index 63f8a7b377..fdf2877ef4 100644 --- a/packages/core/src/actors/transition.ts +++ b/packages/core/src/actors/transition.ts @@ -5,7 +5,8 @@ import { EventObject, ActorRefFrom, AnyActorSystem, - Snapshot + Snapshot, + NonReducibleUnknown } from '../types'; export type TransitionSnapshot = Snapshot & { @@ -15,7 +16,7 @@ export type TransitionSnapshot = Snapshot & { export type TransitionActorLogic< TContext, TEvent extends EventObject, - TInput + TInput extends NonReducibleUnknown > = ActorLogic, TEvent, TInput, AnyActorSystem>; export type TransitionActorRef< @@ -87,7 +88,7 @@ export function fromTransition< TContext, TEvent extends EventObject, TSystem extends ActorSystem, - TInput + TInput extends NonReducibleUnknown >( transition: ( state: TContext, diff --git a/packages/core/src/setup.ts b/packages/core/src/setup.ts index c5cd2a6995..b0b01180ea 100644 --- a/packages/core/src/setup.ts +++ b/packages/core/src/setup.ts @@ -19,6 +19,7 @@ import { SetupTypes, StateSchema, ToChildren, + UnknownActorLogic, Values } from './types'; @@ -102,7 +103,7 @@ type ToStateValue = T extends { export function setup< TContext extends MachineContext, TEvent extends AnyEventObject, // TODO: consider using a stricter `EventObject` here - TActors extends Record, AnyActorLogic>, + TActors extends Record, UnknownActorLogic>, TActions extends Record, TGuards extends Record, TDelay extends string, diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 5013b97872..a3f8fcfa3f 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -2123,7 +2123,7 @@ export type Snapshot = export interface ActorLogic< TSnapshot extends Snapshot, TEvent extends EventObject, - TInput = unknown, + TInput = NonReducibleUnknown, TSystem extends ActorSystem = ActorSystem > { /** The initial setup/configuration used to create the actor logic. */ @@ -2137,7 +2137,7 @@ export interface ActorLogic< * @returns The new state. */ transition: ( - state: TSnapshot, + snapshot: TSnapshot, message: TEvent, ctx: ActorScope ) => TSnapshot; @@ -2184,6 +2184,13 @@ export type AnyActorLogic = ActorLogic< any // system >; +export type UnknownActorLogic = ActorLogic< + any, // this is invariant and it's hard to figure out a better default than `any` + EventObject, + NonReducibleUnknown, + ActorSystem +>; + export type SnapshotFrom = ReturnTypeOrValue extends infer R ? R extends ActorRef ? TSnapshot diff --git a/packages/core/test/setup.types.test.ts b/packages/core/test/setup.types.test.ts index 887b4b3931..f935969961 100644 --- a/packages/core/test/setup.types.test.ts +++ b/packages/core/test/setup.types.test.ts @@ -771,6 +771,28 @@ describe('setup()', () => { }); }); + it(`should provide contextual parameters to input factory for an actor that doesn't specify any input`, () => { + setup({ + types: { + context: {} as { count: number } + }, + actors: { + child: fromPromise(() => Promise.resolve(1)) + } + }).createMachine({ + context: { count: 1 }, + invoke: { + src: 'child', + input: ({ context }) => { + // @ts-expect-error + context.foo; + + return undefined; + } + } + }); + }); + it('should return the correct child type on the available snapshot when the child ID for the actor was configured', () => { const child = createMachine({ types: {} as {