From 147a8a617b3699e8a39bf1c50a411c86bd630f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 27 Apr 2022 12:00:13 +0200 Subject: [PATCH 1/2] Fixed issues with `TEvent` narrowing --- .changeset/few-pianos-begin.md | 5 +++++ .changeset/thin-tools-repair.md | 5 +++++ packages/core/src/types.ts | 15 ++++++++------- packages/core/test/typeHelpers.test.ts | 14 ++++++++++++++ packages/core/test/types.test.ts | 17 +++++++++++++++++ 5 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 .changeset/few-pianos-begin.md create mode 100644 .changeset/thin-tools-repair.md diff --git a/.changeset/few-pianos-begin.md b/.changeset/few-pianos-begin.md new file mode 100644 index 0000000000..a42de9ecee --- /dev/null +++ b/.changeset/few-pianos-begin.md @@ -0,0 +1,5 @@ +--- +'xstate': patch +--- + +Fixed an issue with `EventFrom` not being able to extract events that had a union of strings as their `type` (such as `{ type: 'INC' | 'DEC'; value: number; }`). diff --git a/.changeset/thin-tools-repair.md b/.changeset/thin-tools-repair.md new file mode 100644 index 0000000000..acfe9f9671 --- /dev/null +++ b/.changeset/thin-tools-repair.md @@ -0,0 +1,5 @@ +--- +'xstate': patch +--- + +Fixed an issue with default `TEvent` (`{ type: string }`) not being correctly provided to inline transition actions. diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 93eb30f5d3..db75cc0395 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -455,10 +455,7 @@ export type TransitionConfigOrTarget< export type TransitionsConfigMap = { [K in TEvent['type'] | '' | '*']?: K extends '' | '*' ? TransitionConfigOrTarget - : TransitionConfigOrTarget< - TContext, - TEvent extends { type: K } ? TEvent : never - >; + : TransitionConfigOrTarget>; }; type TransitionsConfigArray = Array< @@ -1657,7 +1654,11 @@ export type Spawnable = export type ExtractEvent< TEvent extends EventObject, TEventType extends TEvent['type'] -> = TEvent extends { type: TEventType } ? TEvent : never; +> = TEvent extends any + ? TEventType extends TEvent['type'] + ? TEvent + : never + : never; export interface BaseActorRef { send: (event: TEvent) => void; @@ -1840,8 +1841,8 @@ type ResolveEventType = ReturnTypeOrValue extends infer R export type EventFrom< T, K extends Prop = never, - TEvent = ResolveEventType -> = IsNever extends true ? TEvent : Extract; + TEvent extends EventObject = ResolveEventType +> = IsNever extends true ? TEvent : ExtractEvent; export type ContextFrom = ReturnTypeOrValue extends infer R ? R extends StateMachine< diff --git a/packages/core/test/typeHelpers.test.ts b/packages/core/test/typeHelpers.test.ts index cef9c857a8..9ac8b9685b 100644 --- a/packages/core/test/typeHelpers.test.ts +++ b/packages/core/test/typeHelpers.test.ts @@ -183,6 +183,20 @@ describe('EventFrom', () => { // @ts-expect-error acceptUserModelEventSubset({ type: 'eventThatDoesNotExist' }); }); + + it('should correctly extract events from events having union of strings as their `type`', () => { + const machine = createMachine({ + schema: { + events: {} as { type: 'INC' | 'DEC' } + } + }); + + type MachineEvent = EventFrom; + + const acceptEvent = (_event: MachineEvent) => {}; + + acceptEvent({ type: 'INC' }); + }); }); describe('MachineOptionsFrom', () => { diff --git a/packages/core/test/types.test.ts b/packages/core/test/types.test.ts index 7489dd6a5e..2e8ed4b646 100644 --- a/packages/core/test/types.test.ts +++ b/packages/core/test/types.test.ts @@ -565,6 +565,23 @@ describe('events', () => { } }); }); + + it('should provide the default TEvent to transition actions when there is no specific TEvent configured', () => { + createMachine({ + schema: { + context: {} as { + count: number; + } + }, + on: { + FOO: { + actions: (_context, event) => { + ((_accept: string) => {})(event.type); + } + } + } + }); + }); }); describe('interpreter', () => { From 0d3e990ff58a9f8357b8584a64fe47e9dbdd80f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 27 Apr 2022 12:12:36 +0200 Subject: [PATCH 2/2] Fixed `model.assign` inference by using old `ExtractEvent` implementation in it --- packages/core/src/model.types.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/core/src/model.types.ts b/packages/core/src/model.types.ts index a66972d50d..badf965e39 100644 --- a/packages/core/src/model.types.ts +++ b/packages/core/src/model.types.ts @@ -5,7 +5,6 @@ import { BaseActionObject, Compute, EventObject, - ExtractEvent, MachineConfig, Prop, PropertyAssigner, @@ -19,6 +18,12 @@ import { TypegenDisabled } from './typegenTypes'; +// real `ExtractEvent` breaks `model.assign` inference within transition actions +type SimplisticExtractEvent< + TEvent extends EventObject, + TEventType extends TEvent['type'] +> = TEvent extends { type: TEventType } ? TEvent : never; + export interface Model< TContext, TEvent extends EventObject, @@ -28,10 +33,10 @@ export interface Model< initialContext: TContext; assign: ( assigner: - | Assigner> - | PropertyAssigner>, + | Assigner> + | PropertyAssigner>, eventType?: TEventType - ) => AssignAction>; + ) => AssignAction>; events: Prop; actions: Prop; reset: () => AssignAction;