Skip to content

Commit

Permalink
[core] Fix type issues with emitted events (#4932)
Browse files Browse the repository at this point in the history
* Fix emitted event types

* Changeset

* Update packages/xstate-solid/src/fromActorRef.ts

Co-authored-by: Christopher Hiller <[email protected]>

* Fix type import

* Update packages/core/test/emit.test.ts

Co-authored-by: Mateusz Burzyński <[email protected]>

* Update packages/core/src/actors/index.ts

Co-authored-by: Mateusz Burzyński <[email protected]>

* Move test

---------

Co-authored-by: Christopher Hiller <[email protected]>
Co-authored-by: Mateusz Burzyński <[email protected]>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent 206e457 commit 71a7f86
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/nervous-chicken-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': patch
---

Actors with emitted events should no longer cause type issues: https://github.com/statelyai/xstate/issues/4931
1 change: 1 addition & 0 deletions packages/core/src/actors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const emptyLogic = fromTransition((_) => undefined, undefined);

export function createEmptyActor(): ActorRef<
Snapshot<undefined>,
AnyEventObject,
AnyEventObject
> {
return createActor(emptyLogic);
Expand Down
9 changes: 7 additions & 2 deletions packages/core/src/createActor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const defaultOptions = {
* An Actor is a running process that can receive events, send events and change its behavior based on the events it receives, which can cause effects outside of the actor. When you run a state machine, it becomes an actor.
*/
export class Actor<TLogic extends AnyActorLogic>
implements ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>>
implements
ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>, EmittedFrom<TLogic>>
{
/**
* The current internal state of the actor.
Expand Down Expand Up @@ -106,7 +107,11 @@ export class Actor<TLogic extends AnyActorLogic>
public _parent?: AnyActorRef;
/** @internal */
public _syncSnapshot?: boolean;
public ref: ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>>;
public ref: ActorRef<
SnapshotFrom<TLogic>,
EventFromLogic<TLogic>,
EmittedFrom<TLogic>
>;
// TODO: add typings for system
private _actorScope: ActorScope<
SnapshotFrom<TLogic>,
Expand Down
24 changes: 14 additions & 10 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ export interface UnifiedArg<
unknown,
TODO // TMeta
>,
TEvent
TEvent,
AnyEventObject
>;
system: AnyActorSystem;
}
Expand Down Expand Up @@ -169,7 +170,7 @@ export type OutputFrom<T> = T extends ActorLogic<
infer _TEmitted
>
? (TSnapshot & { status: 'done' })['output']
: T extends ActorRef<infer TSnapshot, infer _TEvent>
: T extends ActorRef<infer TSnapshot, infer _TEvent, infer _TEmitted>
? (TSnapshot & { status: 'done' })['output']
: never;

Expand Down Expand Up @@ -1521,7 +1522,8 @@ export type ContextFactory<
unknown,
TODO // TMeta
>,
TEvent
TEvent,
AnyEventObject
>;
}) => TContext;

Expand Down Expand Up @@ -1827,7 +1829,8 @@ export type Mapper<
unknown,
TODO // TMeta
>,
TEvent
TEvent,
AnyEventObject
>;
}) => TResult;

Expand Down Expand Up @@ -2181,7 +2184,7 @@ export interface ActorRef<
) => Subscription;
}

export type AnyActorRef = ActorRef<any, any>;
export type AnyActorRef = ActorRef<any, any, any>;

export type ActorLogicFrom<T> = ReturnTypeOrValue<T> extends infer R
? R extends StateMachine<
Expand Down Expand Up @@ -2232,7 +2235,8 @@ export type ActorRefFrom<T> = ReturnTypeOrValue<T> extends infer R
TOutput,
TMeta
>,
TEvent
TEvent,
TEmitted
>
: R extends Promise<infer U>
? ActorRefFrom<PromiseActorLogic<U>>
Expand All @@ -2243,7 +2247,7 @@ export type ActorRefFrom<T> = ReturnTypeOrValue<T> extends infer R
infer _TSystem,
infer TEmitted
>
? ActorRef<TSnapshot, TEvent>
? ActorRef<TSnapshot, TEvent, TEmitted>
: never
: never;

Expand Down Expand Up @@ -2341,7 +2345,7 @@ export interface ActorScope<
TSystem extends AnyActorSystem = AnyActorSystem,
TEmitted extends EventObject = EventObject
> {
self: ActorRef<TSnapshot, TEvent>;
self: ActorRef<TSnapshot, TEvent, TEmitted>;
id: string;
sessionId: string;
logger: (...args: any[]) => void;
Expand Down Expand Up @@ -2469,7 +2473,7 @@ export type UnknownActorLogic = ActorLogic<
>;

export type SnapshotFrom<T> = ReturnTypeOrValue<T> extends infer R
? R extends ActorRef<infer TSnapshot, infer _>
? R extends ActorRef<infer TSnapshot, infer _, infer __>
? TSnapshot
: R extends Actor<infer TLogic>
? SnapshotFrom<TLogic>
Expand Down Expand Up @@ -2541,7 +2545,7 @@ type ResolveEventType<T> = ReturnTypeOrValue<T> extends infer R
infer _TMeta
>
? TEvent
: R extends ActorRef<infer _, infer TEvent>
: R extends ActorRef<infer _TSnapshot, infer TEvent, infer _TEmitted>
? TEvent
: never
: never;
Expand Down
16 changes: 15 additions & 1 deletion packages/core/test/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
sendTo,
spawnChild,
stateIn,
setup
setup,
toPromise
} from '../src/index';

function noop(_x: unknown) {
Expand Down Expand Up @@ -4553,3 +4554,16 @@ describe('snapshot methods', () => {
snapshot.toJSON();
});
});

// https://github.com/statelyai/xstate/issues/4931
it('fromPromise should not have issues with actors with emitted types', () => {
const machine = setup({
types: {
emitted: {} as { type: 'FOO' }
}
}).createMachine({});

const actor = createActor(machine).start();

toPromise(actor);
});
4 changes: 2 additions & 2 deletions packages/xstate-solid/src/fromActorRef.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Accessor, createEffect, createMemo, onCleanup } from 'solid-js';
import { ActorRef, SnapshotFrom } from 'xstate';
import { AnyActorRef, SnapshotFrom } from 'xstate';
import { createImmutable } from './createImmutable.ts';

const noop = () => {};

export function fromActorRef<TActor extends ActorRef<any, any> | undefined>(
export function fromActorRef<TActor extends AnyActorRef | undefined>(
actorRef: Accessor<TActor> | TActor
): Accessor<
| SnapshotFrom<NonNullable<TActor>>
Expand Down

0 comments on commit 71a7f86

Please sign in to comment.